diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/CREDITS linux/CREDITS
--- linux-2.4.16/CREDITS	Mon Nov 26 10:35:00 2001
+++ linux/CREDITS	Wed Dec  5 20:22:25 2001
@@ -1147,6 +1147,16 @@
 S: London SE16 1GD
 S: United Kingdom
 
+N: Jan Harkes
+E: jaharkes@cs.cmu.edu
+W: http://www.coda.cs.cmu.edu/
+D: Coda file system
+S: Computer Science Department
+S: Carnegie Mellon University
+S: 5000 Forbes Avenue
+S: Pittsburgh, Pennsylvania 15213
+S: USA
+
 N: Kai Harrekilde-Petersen
 E: kai.harrekilde@get2net.dk
 D: Original author of the ftape-HOWTO, i82078 fdc detection code.
@@ -1634,6 +1644,13 @@
 S: 80-283 Gdansk
 S: Poland
 
+N: Jakob Kemi
+E: jakob.kemi@telia.com
+D: V4L W9966 Webcam driver
+S: Forsbyvägen 33
+S: 74143 Knivsta
+S: Sweden
+
 N: Gero Kuhlmann
 E: gero@gkminix.han.de
 D: mounting root via NFS
@@ -2495,7 +2512,7 @@
 S: Australia
 
 N: Gerard Roudier
-E: groudier@iplus.fr
+E: groudier@free.fr
 D: Contributed to asynchronous read-ahead improvement
 S: 21 Rue Carnot
 S: 95170 Deuil La Barre
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/Changes linux/Documentation/Changes
--- linux-2.4.16/Documentation/Changes	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/Changes	Thu Dec  6 20:42:51 2001
@@ -53,7 +53,7 @@
 o  binutils               2.9.1.0.25              # ld -v
 o  util-linux             2.10o                   # fdformat --version
 o  modutils               2.4.2                   # insmod -V
-o  e2fsprogs              1.19                    # tune2fs
+o  e2fsprogs              1.25                    # tune2fs
 o  reiserfsprogs          3.x.0j                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
@@ -317,8 +317,7 @@
 
 E2fsprogs
 ---------
-o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19.tar.gz>
-o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19-0.src.rpm>
+o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.25.tar.gz>
 
 Reiserfsprogs
 -------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.16/Documentation/Configure.help	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/Configure.help	Mon Dec 10 18:48:54 2001
@@ -2,10 +2,10 @@
 #	Eric S. Raymond <mailto:esr@thyrsus.com>
 #	Steven Cole <mailto:elenstev@mesatop.com>
 #
-# Merged version 2.49: Current with 2.4.15-pre1 and 2.4.13-ac8.
+# Merged version 2.67: current with 2.4.17-pre5/2.5.1-pre6.
 #
 # This version of the Linux kernel configuration help texts
-# corresponds to the kernel versions 2.4.x.
+# corresponds to kernel versions 2.4.x and 2.5.x.
 #
 # Translations of this file available on the WWW:
 #
@@ -14,11 +14,13 @@
 #   - Russian, by <mailto:kaf@linux.nevod.perm.su>, at
 #     <http://nevod.perm.su/service/linux/doc/kernel/Configure.help>
 #   - French, by Pierre Tane <mailto:tanep@bigfoot.com>, at
-#     <http://www.traduc.org/kernelfr>
+#     <http://www.traduc.org/kernelfr/>
 #   - Polish, by Dominik Mierzejewski <mailto:dmierzej@elka.pw.edu.pl>, at
 #     <http://home.elka.pw.edu.pl/~dmierzej/linux/kernel/>
-#   - German, by SuSE, at <http://www.suse.de/~ke/kernel>. This patch
+#   - German, by SuSE, at <http://www.suse.de/~ke/kernel/>. This patch
 #     also includes infrastructure to support different languages.
+#   - Catalan, by Antoni Bella <mailto:bella5@teleline.es>, at
+#     <http://www.terra.es/personal7/bella5/traduccions.htm>
 #
 # To access a document on the WWW, you need to have a direct Internet
 # connection and a browser program such as netscape or lynx. If you
@@ -133,8 +135,8 @@
 
   See also the <file:Documentation/smp.tex>,
   <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
-  <file:Documentation/nmi_watchdog.txt> and the SMP-FAQ on the WWW at
-  <http://www.irisa.fr/prive/mentre/smp-faq/>.
+  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
 
   If you don't know what to do here, say N.
 
@@ -239,7 +241,7 @@
   You will need a new lynxer.elf file to flash your firmware with - send
   email to Martin.Bligh@us.ibm.com
 
-IO-APIC Support on Uniprocessors
+IO-APIC support on uniprocessors
 CONFIG_X86_UP_IOAPIC
   An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
   SMP-capable replacement for PC-style interrupt controllers. Most
@@ -339,7 +341,7 @@
   "high memory".
 
   If you are compiling a kernel which will never run on a machine with
-  more than 1 Gigabyte total physical RAM, answer "off" here (default
+  more than 960 megabytes of total physical RAM, answer "off" here (default
   choice and suitable for most users). This will result in a "3GB/1GB"
   split: 3GB are mapped so that each process sees a 3GB virtual memory
   space and the remaining part of the 4GB virtual memory space is used
@@ -356,10 +358,10 @@
   processors (Pentium Pro and better). NOTE: If you say "64GB" here,
   then the kernel will not boot on CPUs that don't support PAE!
 
-  The actual amount of total physical memory will either be
-  auto detected or can be forced by using a kernel command line option
-  such as "mem=256M". (Try "man bootparam" or see the documentation of
-  your boot loader (lilo or loadlin) about how to pass options to the
+  The actual amount of total physical memory will either be auto
+  detected or can be forced by using a kernel command line option such
+  as "mem=256M". (Try "man bootparam" or see the documentation of your
+  boot loader (grub, lilo or loadlin) about how to pass options to the
   kernel at boot time.)
 
   If unsure, say "off".
@@ -374,7 +376,7 @@
   Select this if you have a 32-bit processor and more than 4
   gigabytes of physical RAM.
 
-Normal PC floppy disk support
+Normal floppy disk support
 CONFIG_BLK_DEV_FD
   If you want to use the floppy disk drive(s) of your PC under Linux,
   say Y. Information about this driver, especially important for IBM
@@ -577,7 +579,7 @@
 
   To fine-tune ATA/IDE drive/interface parameters for improved
   performance, look for the hdparm package at
-  <http://www.ibiblio.org/pub/Linux/system/hardware>.
+  <ftp://ibiblio.org/pub/Linux/system/hardware/>.
 
   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),
@@ -666,12 +668,9 @@
   CD-ROM drive, you can say N to all other CD-ROM options, but be sure
   to say Y or M to "ISO 9660 CD-ROM file system support".
 
-  Read the CD-ROM-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto> and
-  <file:Documentation/cdrom/ide-cd>. Note that older versions of lilo
-  (the Linux boot loader) cannot properly deal with IDE/ATAPI CD-ROMs,
-  so install lilo-16 or higher, available from
-  <ftp://metalab.unc.edu/pub/Linux/system/boot/lilo>.
+  Note that older versions of LILO (LInux LOader) cannot properly deal
+  with IDE/ATAPI CD-ROMs, so install LILO 16 or higher, available from
+  <ftp://brun.dyndns.org/pub/linux/lilo/>.
 
   If you want to compile the driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -820,7 +819,7 @@
   for these drives, but you can change that by saying Y to the
   following question "Use DMA by default when available". You can get
   the latest version of the hdparm utility from
-  <ftp://metalab.unc.edu/pub/Linux/system/hardware/>.
+  <ftp://ibiblio.org/pub/Linux/system/hardware/>.
 
   Read the comments at the beginning of <file:drivers/ide/ide-dma.c>
   and the file <file:Documentation/ide.txt> for more information.
@@ -899,7 +898,7 @@
 
   It is normally safe to answer Y; however, the default is N.
 
-ATA Work(s) In Progress (EXPERIMENTAL)‹
+ATA Work(s) In Progress (EXPERIMENTAL)
 CONFIG_IDEDMA_PCI_WIP
   If you enable this you will be able to use and test highly
   developmental projects. If you say N, the configurator will
@@ -914,7 +913,7 @@
 
 Pacific Digital A-DMA support (EXPERIMENTAL)
 CONFIG_BLK_DEV_PDC_ADMA
-  Please read the comments at the top of <file:drivers/ide/pdcadma.c>.
+  Please read the comments at the top of <file:drivers/ide/ide-pci.c>.
 
 3ware Hardware ATA-RAID support
 CONFIG_BLK_DEV_3W_XXXX_RAID
@@ -973,7 +972,7 @@
 
   SAY N!
 
-AMD Viper support
+AMD Viper (7401/7409/7411) chipset support
 CONFIG_BLK_DEV_AMD74XX
   This driver ensures (U)DMA support for the AMD756/760 Viper
   chipsets.
@@ -984,7 +983,7 @@
 
   If unsure, say N.
 
-AMD Viper ATA-66 Override (WIP)
+AMD Viper ATA-66 Override support (WIP)
 CONFIG_AMD74XX_OVERRIDE
   This option auto-forces the ata66 flag.
   This effect can be also invoked by calling "idex=ata66"
@@ -1118,11 +1117,13 @@
 
 Special UDMA Feature
 CONFIG_PDC202XX_BURST
-  For PDC20246, PDC20262, PDC20265 and PDC20267 Ultra DMA chipsets.
-  Designed originally for PDC20246/Ultra33 that has BIOS setup
-  failures when using 3 or more cards.
+  This option causes the pdc202xx driver to enable UDMA modes on the
+  PDC202xx even when the PDC202xx BIOS has not done so.
 
-  Unknown for PDC20265/PDC20267 Ultra DMA 100.
+  It was originally designed for the PDC20246/Ultra33, whose BIOS will
+  only setup UDMA on the first two PDC20246 cards.  It has also been
+  used succesfully on a PDC20265/Ultra100, allowing use of UDMA modes
+  when the PDC20265 BIOS has been disabled (for faster boot up).
 
   Please read the comments at the top of
   <file:drivers/ide/pdc202xx.c>.
@@ -1251,15 +1252,6 @@
   <file:Documentation/ide.txt> and <file:drivers/ide/pdc4030.c> files
   for more info.
 
-# This is for Linus's tree.
-QDI QD6580 support
-CONFIG_BLK_DEV_QD6580
-  This driver is enabled at runtime using the "ide0=qd6580" kernel
-  boot parameter.  It permits faster I/O speeds to be set.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/qd6580.c> for
-  more info.
-
-# This is for Alan's tree.  Note the name difference.
 QDI QD65XX support
 CONFIG_BLK_DEV_QD65XX
   This driver is enabled at runtime using the "ide0=qd65xx" kernel
@@ -1488,7 +1480,7 @@
 CONFIG_PARIDE_PG
   This option enables a special high-level driver for generic ATAPI
   devices connected through a parallel port. The driver allows user
-  programs, such as cdrecord, to send ATAPI commands directly to a
+  programs, such as cdrtools, to send ATAPI commands directly to a
   device.
 
   If you chose to build PARIDE support into your kernel, you may
@@ -1502,7 +1494,7 @@
   This driver implements an API loosely related to the generic SCSI
   driver. See <file:include/linux/pg.h>. for details.
 
-  You can obtain the most recent version of cdrecord from
+  You can obtain the most recent version of cdrtools from
   <ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/>. Versions 1.6.1a3 and
   later fully support this driver.
 
@@ -1603,7 +1595,7 @@
   (low speed) adapter that is used in some portable hard drives. If
   you chose to build PARIDE support into your kernel, you may answer Y
   here to build in the protocol driver, otherwise you should answer M
-  to build it as a loadable module. The module will be called ktti.o.
+  to build it as a loadable module. The module will be called fit2.o.
   You must also have a high-level driver for the type of device that
   you want to support.
 
@@ -1716,9 +1708,9 @@
   controller, you do not need to say Y here.
 
   More information about Software RAID on Linux is contained in the
-  Software-RAID mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. There you will also
-  learn where to get the supporting user space utilities raidtools.
+  Software RAID mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. There you will also learn
+  where to get the supporting user space utilities raidtools.
 
   If unsure, say N.
 
@@ -1811,7 +1803,6 @@
 
   If unsure, say N.
 
-# AC tree only
 Support for IDE Raid controllers
 CONFIG_BLK_DEV_ATARAID
   Say Y or M if you have an IDE Raid controller and want linux
@@ -1824,7 +1815,6 @@
   has its own Raid drivers, which you should use if you need better
   performance.
 
-# AC tree only
 Support Promise software RAID (Fasttrak(tm))
 CONFIG_BLK_DEV_ATARAID_PDC
   Say Y or M if you have a Promise Fasttrak (tm) Raid controller
@@ -1835,7 +1825,6 @@
   If you choose to compile this as a module, the module will be called
   pdcraid.o.
 
-# AC tree only
 Highpoint 370 software RAID
 CONFIG_BLK_DEV_ATARAID_HPT
   Say Y or M if you have a Highpoint HPT 370 Raid controller
@@ -1851,19 +1840,19 @@
   This is a machine with a R4400 133/150 MHz CPU. To compile a Linux
   kernel that runs on these, say Y here. For details about Linux on
   the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  <http://oss.sgi.com/mips>.
+  <http://oss.sgi.com/mips/>.
 
 Support for Algorithmics P4032 (EXPERIMENTAL)
 CONFIG_ALGOR_P4032
   This is an evaluation board of the British company Algorithmics.
   The board uses the R4300 and a R5230 CPUs.  For more information
-  about this board see <http://www.algor.co.uk>.
+  about this board see <http://www.algor.co.uk/>.
 
 Support for BAGET MIPS series
 CONFIG_BAGET_MIPS
   This enables support for the Baget, a Russian embedded system.  For
   more details about the Baget see the Linux/MIPS FAQ on
-  <http://oss.sgi.com/mips>.
+  <http://oss.sgi.com/mips/>.
 
 Baget AMD LANCE support
 CONFIG_BAGETLANCE
@@ -1874,8 +1863,8 @@
 Support for DECstations
 CONFIG_DECSTATION
   This enables support for DEC's MIPS based workstations.  For details
-  see the Linux/MIPS FAQ on <http://oss.sgi.com/mips> and the
-  DECstation porting pages on <http://decstation.unix-ag.org>.
+  see the Linux/MIPS FAQ on <http://oss.sgi.com/mips/> and the
+  DECstation porting pages on <http://decstation.unix-ag.org/>.
 
   If you have one of the following DECstation Models you definitely
   want to choose R4xx0 for the CPU Type:
@@ -1904,7 +1893,7 @@
 Support for the Momentum Computer Ocelot SBC
 CONFIG_MOMENCO_OCELOT
   The Ocelot is a MIPS-based Single Board Computer (SBC) made by
-  Momentum Computer <http://www.momenco.com>.
+  Momentum Computer <http://www.momenco.com/>.
 
 Support for NEC DDB Vrc-5074
 CONFIG_DDB5074
@@ -1917,7 +1906,7 @@
   evaluation board.
 
   Features : kernel debugging, serial terminal, NFS root fs, on-board
-  ether port (Need an additional patch at <http://linux.junsun.net>),
+  ether port (Need an additional patch at <http://linux.junsun.net/>),
   USB, AC97, PCI, PCI VGA card & framebuffer console, IDE controller,
   PS2 keyboard, PS2 mouse, etc.
 
@@ -1927,7 +1916,7 @@
   evaluation board.
 
   Features : kernel debugging, serial terminal, NFS root fs, on-board
-  ether port (Need an additional patch at <http://linux.junsun.net>),
+  ether port (Need an additional patch at <http://linux.junsun.net/>),
   USB, AC97, PCI, etc.
 
 Support for MIPS Atlas board
@@ -1953,7 +1942,7 @@
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
   kernel that runs on these, say Y here. For details about Linux on
   the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  <http://oss.sgi.com/mips>.
+  <http://oss.sgi.com/mips/>.
 
 Enable Qtronix 990P Keyboard Support
 CONFIG_QTRONIX_KEYBOARD
@@ -1965,7 +1954,7 @@
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
   kernel that runs on these, say Y here. For details about Linux on
   the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  <http://oss.sgi.com/mips>.
+  <http://oss.sgi.com/mips/>.
 
 Support for SNI RM200 PCI
 CONFIG_SNI_RM200_PCI
@@ -1974,13 +1963,13 @@
   Technology and now in turn merged with Fujitsu.  Say Y here to
   support this machine type.
 
-Support for SGI IP22
+Support for SGI-IP22 (Indy/Indigo2)
 CONFIG_SGI_IP22
   This are the SGI Indy, Challenge S and Indigo2, as well as certain
   OEM variants like the Tandem CMN B006S. To compile a Linux kernel
   that runs on these, say Y here.
 
-Support for SGI IP27
+Support for SGI IP27 (Origin200/2000)
 CONFIG_SGI_IP27
   This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
   workstations.  To compile a Linux kernel that runs on these, say Y
@@ -2036,13 +2025,26 @@
   DZ11-family serial controllers for VAXstations, including the
   DC7085, M7814, and M7819.
 
-
 TURBOchannel support
 CONFIG_TC
   TurboChannel is a DEC (now Compaq) bus for Alpha and MIPS processors.
   Documentation on writing device drivers for TurboChannel is available at:
   <http://www.cs.arizona.edu/computer.help/policy/DIGITAL_unix/AA-PS3HD-TET1_html/TITLE.html>.
 
+# Choice: galileo_clock
+75
+CONFIG_SYSCLK_75
+  Configure the kernel for clock speed of your Galileo board.  
+  The choices are 75MHz, 83.3MHz, and 100MHz.
+
+83.3
+CONFIG_SYSCLK_83
+  Configure the Galileo kernel for a clock speed of 83.3 MHz.
+
+100
+CONFIG_SYSCLK_100
+  Configure the Galileo kernel for a clock speed of 100 MHz.
+
 Z85C30 Serial Support
 CONFIG_ZS
   Documentation on the Zilog 85C350 serial communications controller
@@ -2072,7 +2074,7 @@
 CONFIG_PCMCIA_NINJA_SCSI
   If you intend to attach this type of PCMCIA SCSI host adapter to
   your computer, say Y here and read
-  <file:Documentation/README.nsp_cs>.
+  <file:Documentation/README.nsp_cs.eng>.
 
   This driver is also available as a module called nsp_cs.o ( =
   code which can be inserted in and removed from the running kernel
@@ -2197,7 +2199,7 @@
   Access).  This option is for configuring high-end multiprocessor
   server machines.  If in doubt, say N.
 
-CPU type
+R41xx
 CONFIG_CPU_VR41XX
   The options selects support for the NEC VR41xx series of processors.
   Only choose this option if you have one of these processors as a
@@ -2209,7 +2211,7 @@
   Saying yes here allows you to select support for various features
   your CPU may or may not have.  Most people should say N here.
 
-ll/sc Instructions available
+ll and sc instructions available
 CONFIG_CPU_HAS_LLSC
   MIPS R4000 series and later provide the Load Linked (ll)
   and Store Conditional (sc) instructions. More information is
@@ -2219,7 +2221,7 @@
   for better performance, N if you don't know.  You must say Y here
   for multiprocessor machines.
 
-lld and scd instructions
+lld and scd instructions available
 CONFIG_CPU_HAS_LLDSCD
   Say Y here if your CPU has the lld and scd instructions, the 64-bit
   equivalents of ll and sc.  Say Y here for better performance, N if
@@ -2263,7 +2265,7 @@
   of which are given in <file:Documentation/Changes>.
 
   For a general introduction to Linux networking, it is highly
-  recommended to read the NET-3-HOWTO, available from
+  recommended to read the NET-HOWTO, available from
   <http://www.linuxdoc.org/docs.html#howto>.
 
 Socket filtering
@@ -2352,7 +2354,7 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-IRC Send/Chat support
+IRC Send/Chat protocol support
 CONFIG_IP_NF_IRC
   There is a commonly-used extension to IRC called
   Direct Client-to-Client Protocol (DCC).  This enables users to send
@@ -2436,7 +2438,7 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
-length match support
+LENGTH match support
 CONFIG_IP_NF_MATCH_LENGTH
   This option allows you to match the length of a packet against a
   specific value or range of values.
@@ -2658,6 +2660,23 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+Multiple port match support
+CONFIG_IP6_NF_MATCH_MULTIPORT
+  Multiport matching allows you to match TCP or UDP packets based on
+  a series of source or destination ports: normally a rule can only
+  match a single range of ports.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+Owner match support
+CONFIG_IP6_NF_MATCH_OWNER
+  Packet owner matching allows you to match locally-generated packets
+  based on who created them: the user, group, process or session.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
 Packet filtering
 CONFIG_IP6_NF_FILTER
   Packet filtering defines a table `filter', which has a series of
@@ -2724,6 +2743,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+LOG target support
+CONFIG_IP6_NF_TARGET_LOG
+  This option adds a `LOG' target, which allows you to create rules in
+  any iptables table which records the packet header to the syslog.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
 SYN flood protection
 CONFIG_SYN_COOKIES
   Normal TCP/IP networking is open to an attack known as "SYN
@@ -2776,7 +2803,7 @@
 
   To find out what type of Alpha system you have, you may want to
   check out the Linux/Alpha FAQ, accessible on the WWW from
-  <http://www.alphalinux.org>. In summary:
+  <http://www.alphalinux.org/>. In summary:
 
   Alcor/Alpha-XLT     AS 600
   Alpha-XL            XL-233, XL-266
@@ -2955,13 +2982,18 @@
 CONFIG_ALPHA_GAMMA
   Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
 
+EV67 (or later) CPU (speed > 600MHz)?
+CONFIG_ALPHA_EV67
+  Is this a machine based on the EV67 core?  If in doubt, select N here
+  and the machine will be treated as an EV6.
+
 Use SRM as bootloader
 CONFIG_ALPHA_SRM
   There are two different types of booting firmware on Alphas: SRM,
   which is command line driven, and ARC, which uses menus and arrow
   keys. Details about the Linux/Alpha booting process are contained in
   the Linux/Alpha FAQ, accessible on the WWW from
-  <http://www.alphalinux.org>.
+  <http://www.alphalinux.org/>.
 
   The usual way to load Linux on an Alpha machine is to use MILO
   (a bootloader that lets you pass command line parameters to the
@@ -3130,7 +3162,7 @@
 
   The user level application needed to use this driver can be found at
   the IBM Linux Technology Center (LTC) web site:
-  http://www.ibm.com/linux/ltc/
+  <http://www.ibm.com/linux/ltc/>.
 
   If you own one of the above IBM Thinkpads which has the Mwave chipset
   in it, say Y.
@@ -3300,7 +3332,7 @@
 
   When in doubt, say Y.
 
-PCI Hotplug support
+Generic PCI hotplug support
 CONFIG_HOTPLUG_PCI
   Say Y here if you have a motherboard with a PCI Hotplug controller.
   This allows you to add and remove PCI cards while the machine is
@@ -3314,7 +3346,7 @@
 
   When in doubt, say N.
 
-PCI Compaq Hotplug controller
+Compaq PCI Hotplug driver
 CONFIG_HOTPLUG_PCI_COMPAQ
   Say Y here if you have a motherboard with a Compaq PCI Hotplug
   controller.
@@ -3505,7 +3537,7 @@
   example, used on modern desktops as well as laptops, is USB.
 
   Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-  software (at <http://linux-hotplug.sourceforge.net>) and install it.
+  software (at <http://linux-hotplug.sourceforge.net/>) and install it.
   Then your kernel will automatically call out to a user mode "policy
   agent" (/sbin/hotplug) to load modules and set up software needed
   to use devices as you hotplug them.
@@ -3547,6 +3579,12 @@
 
   If unsure, say Y.
 
+i82092 compatible bridge support
+CONFIG_I82092
+  This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
+  found in some older laptops and more commonly in evaluation boards for the
+  chip.
+
 i82365 compatible host bridge support
 CONFIG_I82365
   Say Y here to include support for ISA-bus PCMCIA host bridges that
@@ -3625,7 +3663,6 @@
   don't understand what this means or are not a kernel hacker, just
   leave it at its default value ELF.
 
-# Choice: kcore
 Select a.out format for /proc/kcore
 CONFIG_KCORE_AOUT
   Not necessary unless you're using a very out-of-date binutils
@@ -3748,7 +3785,7 @@
   The module will be called envctrl.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-# Choice: x86
+# Choice: x86type
 Processor family
 CONFIG_M386
   This is the processor type of your CPU. This information is used for
@@ -3821,7 +3858,7 @@
 
   The program SVGATextMode can be used to utilize SVGA video cards to
   their full potential in text mode. Download it from
-  <ftp://metalab.unc.edu/pub/Linux/utils/console>.
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
 
   Say Y.
 
@@ -4053,21 +4090,18 @@
   module will be called aty128fb.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-# AC tree only
 Maxine (Personal DECstation) onboard framebuffer support
 CONFIG_FB_MAXINE
   Say Y here to directly support the on-board framebuffer in the
   Maxine (5000/20, /25, /33) version of the DECstation.  There is a
   page dedicated to Linux on DECstations at <http://decstation.unix-ag.org/>.
 
-# AC tree only
 PMAG-BA TURBOchannel framebuffer support
 CONFIG_FB_PMAG_BA
   Say Y here to directly support the on-board PMAG-BA framebuffer in
   the 5000/1xx versions of the DECstation.  There is a page dedicated
   to Linux on DECstations at <http://decstation.unix-ag.org/>.
 
-# AC tree only
 PMAGB-B TURBOchannel framebuffer support
 CONFIG_FB_PMAGB_B
   Say Y here to directly support the on-board PMAGB-B framebuffer in
@@ -4079,10 +4113,32 @@
   Say Y here if you intend to run this kernel on a FutureTV (nee Nexus
   Electronics) StrongARM PCI card.
 
-P720T
-CONFIG_ARCH_P720T
-  Say Y here if you intend to run this kernel on the ARM Prospector
-  720T.
+ANAKIN Vehicle Telematics Platform
+CONFIG_ARCH_ANAKIN
+  The Anakin is a StrongArm based SA110 - 2 DIN Vehicle Telematics Platform.
+  64MB SDRAM - 4 Mb Flash - Compact Flash Interface - 1 MB VRAM
+
+  On board peripherals:
+        * Front display: 400x234 16 bit TFT touchscreen
+        * External independent second screen interface
+        * CAN controller SJA1000
+        * USB host controller
+        * 6 channel video codec with hardware overlay
+        * Smartcard reader
+        * IrDa
+
+  Modules interfaced over the Multi Media Extension slots:
+        * A communication card
+                Wavecom GPRS modem
+                uBlock GPS
+                Bosch DAB module
+        * An audio card ( 4 * 40W, AC97 Codec, I2S)
+
+Altera Excalibur XA10 Dev Board
+ARCH_CAMELOT
+  This enables support for Altera's Excalibur XA10 development board.
+  If you would like to build your kernel to run on one of these boards
+  then you must say 'Y' here. Otherwise say 'N'
 
 Link-Up Systems LCD support
 CONFIG_FB_L7200
@@ -4306,10 +4362,8 @@
   a module, say M here and read <file:Documentation/modules.txt>.
 
   You can pass several parameters to the driver at boot time or at
-  module load time. The parameters look like "video=matrox:XXX", where
-  the meaning of XXX can be found at the end of the main source file
-  (<file:drivers/video/matroxfb.c>). Please see
-  <file:Documentation/fb/matroxfb.txt>.
+  module load time. The parameters look like "video=matrox:XXX", and
+  are described in <file:Documentation/fb/matroxfb.txt>.
 
 Matrox Millennium I/II support
 CONFIG_FB_MATROX_MILLENIUM
@@ -4372,7 +4426,7 @@
 
   The driver starts in monitor mode and you must use the matroxset
   tool (available at
-  <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest>) to switch it to
+  <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to switch it to
   PAL or NTSC or to swap primary and secondary head outputs.
   Secondary head driver also always start in 640x480 resolution, you
   must use fbset to change it.
@@ -4394,7 +4448,7 @@
 
   The driver starts in monitor mode and currently does not support
   output in TV modes.  You must use the matroxset tool (available
-  at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest>) to swap
+  at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to swap
   primary and secondary head outputs.  Secondary head driver always
   start in 640x480 resolution and you must use fbset to change it.
 
@@ -4504,19 +4558,17 @@
   This is the frame buffer device driver for the Hitachi HD64461 LCD
   frame buffer card.
 
-SIS 630/540 display support
+SIS acceleration
 CONFIG_FB_SIS
   This is the frame buffer device driver for the SiS 630 and 640 Super
   Socket 7 UMA cards.  Specs available at <http://www.sis.com.tw/>.
 
-# AC tree only
 SIS 630/540/730 support
 CONFIG_FB_SIS_300
   This is the frame buffer device driver for the SiS 630 and related
   Super Socket 7 UMA cards.  Specs available at
   <http://www.sis.com.tw/>.
 
-# AC tree only
 SIS 315H/315 support
 CONFIG_FB_SIS_315
   This is the frame buffer device driver for the SiS 315 graphics
@@ -4570,7 +4622,6 @@
   is at
   <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
 
-# AC tree only
 ATI Radeon display support
 CONFIG_FB_RADEON
   Choose this option if you want to use an ATI Radeon graphics card as
@@ -4697,7 +4748,8 @@
   drive, PLIP link (Parallel Line Internet Protocol is mainly used to
   create a mini network by connecting the parallel ports of two local
   machines) etc., then you need to say Y here; please read
-  <file:Documentation/parport.txt> and drivers/parport/BUGS-parport.
+  <file:Documentation/parport.txt> and
+  <file:drivers/parport/BUGS-parport>.
 
   For extensive information about drivers for many devices attaching
   to the parallel port see <http://www.torque.net/linux-pp.html> on
@@ -4729,7 +4781,7 @@
 
   If unsure, say Y.
 
-Parallel+serial PCI card support
+Parallel+serial PCI multi-IO card support
 CONFIG_PARPORT_SERIAL
   This adds support for multi-IO PCI cards that have parallel and
   serial ports.  You should say Y or M here.  If you say M, the module
@@ -5154,6 +5206,7 @@
 
   It is safe to say N here for now.
 
+# 2.5 tree only
 IPv6: routing messages via old netlink
 CONFIG_IPV6_NETLINK
   You can say Y here to receive routing messages from the IPv6 code
@@ -5186,7 +5239,7 @@
   used for local networks of Windows machines.  You need it if you
   want to access Novell NetWare file or print servers using the Linux
   Novell client ncpfs (available from
-  <ftp://metalab.unc.edu/pub/Linux/system/filesystems/>) or from
+  <ftp://platan.vc.cvut.cz/pub/linux/ncpfs/>) or from
   within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO,
   available from <http://www.linuxdoc.org/docs.html#howto>).  In order
   to do the former, you'll also have to say Y to "NCP file system
@@ -5198,8 +5251,8 @@
 
   To turn your Linux box into a fully featured NetWare file server and
   IPX router, say Y here and fetch either lwared from
-  <ftp://metalab.unc.edu/pub/Linux/system/network/daemons/> or
-  mars_nwe from <ftp://ftp.gwdg.de/pub/linux/misc/ncpfs>. For more
+  <ftp://ibiblio.org/pub/Linux/system/network/daemons/> or
+  mars_nwe from <ftp://www.compu-art.de/mars_nwe/>. For more
   information, read the IPX-HOWTO available from
   <http://www.linuxdoc.org/docs.html#howto>.
 
@@ -5235,7 +5288,7 @@
   'special' sockets to sockets listening on the primary network is
   disabled. This might break existing applications, especially RIP/SAP
   daemons. A RIP/SAP daemon that works well with the full internal net
-  can be found on <ftp://ftp.gwdg.de/pub/linux/misc/ncpfs>.
+  can be found on <ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/>.
 
   If you don't know what you are doing, say N.
 
@@ -5303,7 +5356,7 @@
   network link driver", "Routing messages" and "Network packet
   filtering".  The first two are required to allow configuration via
   rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
-  from <ftp://ftp.inr.ac.ru>). The "Network packet filtering" option
+  from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option
   will be required for the forthcoming routing daemon to work.
 
   See <file:Documentation/networking/decnet.txt> for more information.
@@ -5424,9 +5477,8 @@
 Amateur Radio support
 CONFIG_HAMRADIO
   If you want to connect your Linux box to an amateur radio, answer Y
-  here. You want to read <http://www.tapr.org/tapr/html/pkthome.html>
-  and the HAM-HOWTO and the AX25-HOWTO, both available from
-  <http://www.linuxdoc.org/docs.html#howto>.
+  here. You want to read <http://www.tapr.org/tapr/html/pkthome.html> and
+  the AX25-HOWTO, available from <http://www.linuxdoc.org/docs.html#howto>.
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause the configurator to skip all
@@ -5633,7 +5685,7 @@
   connect to a parallel interface. The driver supports the picpar and
   par96 designs. To configure the driver, use the sethdlc utility
   available in the standard ax25 utilities package. For information on
-  the modems, see <http://www.baycom.de> and the file
+  the modems, see <http://www.baycom.de/> and the file
   <file:Documentation/networking/baycom.txt>.
 
   If you want to compile this driver as a module ( = code which can be
@@ -5647,7 +5699,7 @@
   connect to a parallel interface. The driver supports the EPP
   designs. To configure the driver, use the sethdlc utility available
   in the standard ax25 utilities package. For information on the
-  modems, see <http://www.baycom.de> and the file
+  modems, see <http://www.baycom.de/> and the file
   <file:Documentation/networking/baycom.txt>.
 
   If you want to compile this driver as a module ( = code which can be
@@ -5666,7 +5718,7 @@
   driver and still provided in case this driver does not work with
   your serial interface chip. To configure the driver, use the sethdlc
   utility available in the standard ax25 utilities package. For
-  information on the modems, see <http://www.baycom.de> and
+  information on the modems, see <http://www.baycom.de/> and
   <file:Documentation/networking/baycom.txt>.
 
   If you want to compile this driver as a module ( = code which can be
@@ -5683,7 +5735,7 @@
   the full-duplex driver. This driver is depreciated.  To configure
   the driver, use the sethdlc utility available in the standard ax25
   utilities package. For information on the modems, see
-  <http://www.baycom.de> and
+  <http://www.baycom.de/> and
   <file:Documentation/networking/baycom.txt>.
 
   If you want to compile this driver as a module ( = code which can be
@@ -5860,7 +5912,7 @@
    - etc...
 
   For more informations, please refer to:
-    <http://www.freshmeat.net/projects/etherdivert>
+    <http://diverter.sourceforge.net/>
     <http://perso.wanadoo.fr/magpie/EtherDivert.html>
 
   If unsure, say N.
@@ -5915,14 +5967,14 @@
 
   If unsure, say N.
 
+# 2.5 tree only
 Kernel/User network link driver
 CONFIG_NETLINK
   This driver allows for two-way communication between the kernel and
   user processes.  It does so by creating a new socket family,
   PF_NETLINK.  Over this socket, the kernel can send and receive
   datagrams carrying information.  It is documented on many systems in
-  netlink(7), a HOWTO is provided as well, for example on
-  <http://snafu.freedom.org/linux2.2/docs/netlink-HOWTO.html>.
+  netlink(7).
 
   So far, the kernel uses this feature to publish some network related
   information if you say Y to "Routing messages", below. You also need
@@ -5934,11 +5986,12 @@
 
   If unsure, say Y.
 
+# 2.5 tree only
 Routing messages
 CONFIG_RTNETLINK
   If you say Y here, user space programs can receive some network
   related routing information over the netlink. 'rtmon', supplied
-  with the iproute2 package (<ftp://ftp.inr.ac.ru>), can read and
+  with the iproute2 package (<ftp://ftp.inr.ac.ru/>), can read and
   interpret this data.  Information sent to the kernel over this link
   is ignored.
 
@@ -6225,7 +6278,7 @@
   control memory (128K-1KVC, 512K-4KVC), the size of the packet
   memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3,
   UTP155, UTP25, DS3 and E3). Go to:
-  	www.iphase.com/products/ClassSheet.cfm?ClassID=ATM
+  	<http://www.iphase.com/products/ClassSheet.cfm?ClassID=ATM>
   for more info about the cards. Say Y (or M to compile as a module
   named iphase.o) here if you have one of these cards.
 
@@ -6238,7 +6291,7 @@
   messages is controlled by a bitmap. This may be specified as a
   module argument (kernel command line argument as well?), changed
   dynamically using an ioctl (Get the debug utility, iadbg, from
-  <ftp://ftp.iphase.com/pub/atm/pci>).
+  <ftp://ftp.iphase.com/pub/atm/pci/>).
 
   See the file <file:drivers/atm/iphase.h> for the meanings of the
   bits in the mask.
@@ -6247,6 +6300,13 @@
   speed of the driver, and the size of your syslog files! When
   inactive, they will have only a modest impact on performance.
 
+Efficient Networks Speedstream 3010
+CONFIG_ATM_LANAI
+  Supports ATM cards based on the Efficient Networks "Lanai"
+  chipset such as the Speedstream 3010 and the ENI-25p.  The
+  Speedstream 3060 is currently not supported since we don't
+  have the code to drive the on-board Alcatel DSL chipset (yet).
+
 Linux telephony support
 CONFIG_PHONE
   Say Y here if you have a telephony card, which for example allows
@@ -6365,6 +6425,13 @@
   the performances of the driver, and the size of your syslog files!
   Keep the debugging level to 0 during normal operations.
 
+PPP over ATM
+CONFIG_PPPOATM
+  Support PPP (Point to Point Protocol) encapsulated in ATM frames.
+  This implementation does not yet comply with section 8 of RFC2364,
+  which can lead to bad results idf the ATM peer loses state and 
+  changes its encapsulation unilaterally.
+
 Fusion MPT device support
 CONFIG_FUSION
   LSI Logic Fusion(TM) Message Passing Technology (MPT) device support
@@ -6490,12 +6557,6 @@
   You also need to say Y here if you want support for the parallel
   port version of the 100 MB IOMEGA ZIP drive.
 
-  Please read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. The
-  SCSI-Programming-HOWTO contains information about how to add or
-  remove an SCSI device from a running Linux machine without
-  rebooting.
-
   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 scsi_mod.o.  If you want to compile it as
@@ -6573,7 +6634,7 @@
   tape drives (ADR-x0) that supports the standard SCSI-2 commands for
   tapes (QIC-157) and can be driven by the standard driver st.
   For more information, you may have a look at the SCSI-HOWTO
-  <ftp://metalab.unc.edu/pub/Linux/docs/HOWTO>  and
+  <http://www.linuxdoc.org/docs.html#howto>  and
   <file:drivers/scsi/README.osst>  in the kernel source.
   More info on the OnStream driver may be found on
   <http://linux1.onstream.nl/test/>
@@ -6628,12 +6689,12 @@
   directly, so you need some additional software which knows how to
   talk to these devices using the SCSI protocol:
 
-  For scanners, look at SANE (<http://www.mostang.com/sane>). For CD
-  writer software look at cdrecord
+  For scanners, look at SANE (<http://www.mostang.com/sane/>). For CD
+  writer software look at Cdrtools
   (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
-  and for burning a "disk at once": cdrdao
-  (<http://www.ping.de/sites/daneb/cdrdao.html>). Cdparanoia is a high
-  quality digital reader of audio CDs (<http://www.xiph.org/paranoia>).
+  and for burning a "disk at once": CDRDAO
+  (<http://cdrdao.sourceforge.net/>). Cdparanoia is a high
+  quality digital reader of audio CDs (<http://www.xiph.org/paranoia/>).
   For other devices, it's possible that you'll have to write the
   driver software yourself. Please read the file
   <file:Documentation/scsi-generic.txt> for more information.
@@ -6644,17 +6705,6 @@
   <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
   say N.
 
-Enable extra checks in SCSI queueing code
-CONFIG_SCSI_DEBUG_QUEUES
-  This option turns on a lot of additional consistency checking for
-  the new queueing code. This will adversely affect performance, but
-  it is likely that bugs will be caught sooner if this is turned on.
-  This will typically cause the kernel to panic if an error is
-  detected, but it would have probably crashed if the panic weren't
-  there. Comments/questions/problems to linux-scsi mailing list
-  please. See <http://www.andante.org/scsi_queue.html> for more
-  up-to-date information.
-
 Probe all LUNs on each SCSI device
 CONFIG_SCSI_MULTI_LUN
   If you have a SCSI device that supports more than one LUN (Logical
@@ -6768,7 +6818,7 @@
   intended to replace the previous aic7xxx driver maintained by Doug
   Ledford since Doug is no longer maintaining that driver.
 
-Adaptec I2O RAID controllers
+Adaptec I2O RAID support
 CONFIG_SCSI_DPT_I2O
   This driver supports all of Adaptec's I2O based RAID controllers as 
   well as the DPT SmartRaid V cards.  This is an Adaptec maintained
@@ -6941,10 +6991,10 @@
   This is support for BusLogic MultiMaster and FlashPoint SCSI Host
   Adapters. Consult the SCSI-HOWTO, available from
   <http://www.linuxdoc.org/docs.html#howto>, and the files
-  README.BusLogic and README.FlashPoint in drivers/scsi for more
-  information. If this driver does not work correctly without
-  modification, please contact the author, Leonard N. Zubkoff, by
-  email to lnz@dandelion.com.
+  <file:drivers/scsi/README.BusLogic> and
+  <file:drivers/scsi/README.FlashPoint> for more information. If this
+  driver does not work correctly without modification, please contact
+  the author, Leonard N. Zubkoff, by email to lnz@dandelion.com.
 
   You can also build this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -7121,7 +7171,7 @@
   Unless you have an NCR manufactured machine, the chances are that
   you do not have this SCSI card, so say N.
 
-HP LASI SCSI support for 53c700
+HP LASI SCSI support for 53c700/710
 CONFIG_SCSI_LASI700
   This is a driver for the lasi baseboard in some parisc machines
   which is based on the 53c700 chip.  Will also support LASI subsystems
@@ -7186,7 +7236,7 @@
   If your system has problems using this new major version of the
   SYM53C8XX driver, you may switch back to driver version 1.
 
-  Please read drivers/scsi/sym53c8xx_2/Documentation.txt for more
+  Please read <file:drivers/scsi/sym53c8xx_2/Documentation.txt> for more
   information.
 
 PCI DMA addressing mode
@@ -7727,7 +7777,7 @@
 NCR53c406a SCSI support
 CONFIG_SCSI_NCR53C406A
   This is support for the NCR53c406a SCSI host adapter.  For user
-  configurable parameters, check out <file:drivers/scsi/NCR53c406.c>
+  configurable parameters, check out <file:drivers/scsi/NCR53c406a.c>
   in the kernel source.  Also read the SCSI-HOWTO, available from
   <http://www.linuxdoc.org/docs.html#howto>.
 
@@ -7833,13 +7883,14 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called megaraid.o.
 
-Intel/ICP (former GDT SCSI Disk Array) RAID Controller Support
+Intel/ICP (former GDT SCSI Disk Array) RAID Controller support
 CONFIG_SCSI_GDTH
   Formerly called GDT SCSI Disk Array Controller Support.
  
   This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) 
   manufactured by Intel/ICP vortex (an Intel Company). It is documented
-  in the kernel source in drivers/scsi/gdth.c and drivers/scsi/gdth.h. 
+  in the kernel source in <file:drivers/scsi/gdth.c> and
+  <file:drivers/scsi/gdth.h.>
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -8122,7 +8173,7 @@
 #  say M here and read <file:Documentation/modules.txt>.  The module
 #  will be called aic5800.o.
 #
-OHCI-1394 support
+OHCI-1394 (Open Host Controller Interface) support
 CONFIG_IEEE1394_OHCI1394
   Enable this driver if you have an IEEE 1394 controller based on the
   OHCI-1394 specification. The current driver is only tested with OHCI
@@ -8252,8 +8303,8 @@
 
   Normally, your access provider has to support SLIP in order for you
   to be able to use it, but there is now a SLIP emulator called SLiRP
-  around (available via FTP (user: anonymous) from
-  <ftp://metalab.unc.edu/pub/Linux/system/network/serial/>) which
+  around (available from
+  <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
   allows you to use SLIP over a regular dial up shell connection. If
   you plan to use SLiRP, make sure to say Y to CSLIP, below. The
   NET-3-HOWTO, available from
@@ -8278,7 +8329,7 @@
   on both ends. Ask your access provider if you are not sure and
   answer Y, just in case. You will still be able to use plain SLIP. If
   you plan to use SLiRP, the SLIP emulator (available from
-  <ftp://metalab.unc.edu/pub/Linux/system/network/serial/>) which
+  <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
   allows you to use SLIP over a regular dial up shell connection, you
   definitely want to say Y here. The NET-3-HOWTO, available from
   <http://www.linuxdoc.org/docs.html#howto>, explains how to configure
@@ -8415,7 +8466,7 @@
 
   This driver requires a specially patched pppd daemon.  The patch to
   pppd, along with binaries of a patched pppd package can be found at:
-  <http://www.shoshin.uwaterloo.ca/~mostrows>.
+  <http://www.shoshin.uwaterloo.ca/~mostrows/>.
 
 Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
@@ -8437,7 +8488,7 @@
 
   Some user-level drivers for scarab devices which don't require
   special kernel support are available from
-  <ftp://shadow.cabi.net/pub/Linux>.
+  <ftp://shadow.cabi.net/pub/Linux/>.
 
 STRIP (Metricom Starmode radio IP)
 CONFIG_STRIP
@@ -8684,6 +8735,19 @@
   a module, say M here and read <file:Documentation/modules.txt>. If
   unsure, say N.
 
+Asix AX88190 PCMCIA support
+CONFIG_PCMCIA_AXNET
+  Say Y here if you intend to attach an Asix AX88190-based PCMCIA
+  (PC-card) Fast Ethernet card to your computer.  These cards are
+  nearly NE2000 compatible but need a separate driver due to a few
+  misfeatures.
+
+  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 axnet_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
 New Media PCMCIA support
 CONFIG_PCMCIA_NMCLAN
   Say Y here if you intend to attach a New Media Ethernet or LiveWire
@@ -8739,7 +8803,7 @@
   The module will be called ibmtr_cs.o.  If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
-Xircom Tulip-like CardBus support
+Xircom Tulip-like CardBus support (old driver)
 CONFIG_PCMCIA_XIRTULIP
   This driver is for the Digital "Tulip" Ethernet CardBus adapters.
   It should work with most DEC 21*4*-based chips/ethercards, as well
@@ -8783,12 +8847,6 @@
   configure your card and that /etc/pcmcia/wireless.opts works :
   <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
 
-Apple Airport support (built-in)
-CONFIG_APPLE_AIRPORT
-  Enable support for the Apple Airport card (which is essentially a
-  Lucent Orinoco card with a non-standard interface) built into some
-  newer Apple Macintosh machines.
-
 Hermes 802.11b in PLX9052 based PCI adaptor support
 CONFIG_PLX_HERMES
   Enable support for PCMCIA cards supported by the "Hermes" (aka
@@ -8870,7 +8928,8 @@
 CONFIG_APPLE_AIRPORT
   Say Y here to support the Airport 802.11b wireless Ethernet hardware
   built into the Macintosh iBook and other recent PowerPC-based
-  Macintosh machines.
+  Macintosh machines. This is essentially a Lucent Orinoco card with 
+  a non-standard interface
 
 Xircom Netwave AirSurfer wireless support
 CONFIG_PCMCIA_NETWAVE
@@ -9015,7 +9074,7 @@
   of the Cisco HDLC/PPP driver (syncppp.c).
   The SyncLink WAN driver (in character devices) must also be enabled.
 
-FarSync T-Series support
+FarSync T-Series X.21 (and V.35/V.24) cards
 CONFIG_FARSYNC
   This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
   from FarSite Communications Ltd.
@@ -9118,7 +9177,7 @@
   the price of an external router.  If you have one of those cards and
   wish to use your Linux box as a WAN router, say Y here and also to
   the WAN driver for your card, below.  You will then need the
-  wan-tools package which is available from <ftp://ftp.sangoma.com>.
+  wan-tools package which is available from <ftp://ftp.sangoma.com/>.
   Read <file:Documentation/networking/wan-router.txt> for more
   information.
 
@@ -9500,7 +9559,7 @@
   up. Look at the <http://www.fi.muni.cz/~kas/cosa/> for more
   information about the cards (including the pointer to the user-space
   utilities). You can also read the comment at the top of the
-  <file:drivers/net/cosa.c> for details about the cards and the driver
+  <file:drivers/net/wan/cosa.c> for details about the cards and the driver
   itself.
 
   The driver will be compiled as a module ( = code which can be
@@ -9512,7 +9571,7 @@
 CONFIG_DSCC4
   This is a driver for Etinc PCISYNC boards based on the Infineon
   (ex. Siemens) DSCC4 chipset. It is supposed to work with the four
-  ports card. Take a look at <http://www.cogenit.fr/dscc4>
+  ports card. Take a look at <http://www.cogenit.fr/dscc4/>
   for further informations about the driver and his configuration.
 
   The driver will be compiled as a module ( = code which can be
@@ -9539,7 +9598,7 @@
   additional external hardware.
 
   To change setting such as syncPPP vs cisco HDLC or clock source you
-  will need lmcctl.  It is available at <ftp://ftp.lanmedia.com>.
+  will need lmcctl.  It is available at <ftp://ftp.lanmedia.com/>.
 
   This code is also available as a module called lmc.o ( = code
   which can be inserted in and removed from the running kernel
@@ -9584,12 +9643,12 @@
   module will be called sbni.o).
 
   You can find more information and last versions of drivers and
-  utilities at <http://www.granch.ru>. If you have any question you
+  utilities at <http://www.granch.ru/>. If you have any question you
   can send email to sbni@granch.ru.
 
   Say N if unsure.
 
-SBNI Adapters Multiline feature
+SBNI multiple-line feature support
 CONFIG_SBNI_MULTILINE
   Schedule traffic for some parallel lines, via SBNI12 adapters.
   If you have two computers connected with two parallel lines it's
@@ -9607,7 +9666,7 @@
   Router".
 
   You will need the wan-tools package which is available from
-  <ftp://ftp.sangoma.com>. Read
+  <ftp://ftp.sangoma.com/>. Read
   <file:Documentation/networking/wan-router.txt> for more information.
 
   Note that the answer to this question won't directly affect the
@@ -9616,7 +9675,7 @@
 
 Sangoma WANPIPE(tm) multiprotocol cards
 CONFIG_VENDOR_SANGOMA
-  WANPIPE from Sangoma Technologies Inc. (<http://www.sangoma.com>)
+  WANPIPE from Sangoma Technologies Inc. (<http://www.sangoma.com/>)
   is a family of intelligent multiprotocol WAN adapters with data
   transfer rates up to 4Mbps. They are also known as Synchronous
   Data Link Adapters (SDLA) and are designated as S514-PCI or
@@ -9704,7 +9763,7 @@
 
   Read <file:Documentation/networking/comx.txt> for help on
   configuring and using COMX interfaces.  Further info on these cards
-  can be found at <http://www.itc.hu> or <info@itc.hu>.
+  can be found at <http://www.itc.hu/> or <info@itc.hu>.
 
   You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
   use this driver.
@@ -9798,8 +9857,8 @@
 
 Cyclom 2X(tm) multiprotocol cards
 CONFIG_CYCLADES_SYNC
-  Cyclom 2X from Cyclades Corporation (<http://www.cyclades.com> and
-  <http://www.cyclades.com.br)> is an intelligent multiprotocol WAN
+  Cyclom 2X from Cyclades Corporation (<http://www.cyclades.com/> and
+  <http://www.cyclades.com.br/>) is an intelligent multiprotocol WAN
   adapter with data transfer rates up to 512 Kbps. These cards support
   the X.25 and SNA related protocols. If you have one or more of these
   cards, say Y to this option. The next questions will ask you about
@@ -9808,10 +9867,10 @@
 
   While no documentation is available at this time please grab the
   wanconfig tarball in
-  <http://www.conectiva.com.br/~acme/cycsyn-devel> (with minor changes
+  <http://www.conectiva.com.br/~acme/cycsyn-devel/> (with minor changes
   to make it compile with the current wanrouter include files; efforts
   are being made to use the original package available at
-  <ftp://ftp.sangoma.com>).
+  <ftp://ftp.sangoma.com/>).
 
   Feel free to contact me or the cycsyn-devel mailing list at
   acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
@@ -10288,15 +10347,7 @@
   is a 10Mbit/sec Ethernet controller.  Product overview and specs at
   <http://www.national.com/pf/DP/DP83902A.html>.
 
-CompactFlash Connection Area
-CONFIG_CF_AREA5
-  If your board has "Directly Connected" CompactFlash, You should
-  select the area where your CF is connected to.
-
-  - "Area5" if CompactFlash is connected to Area 5 (0x14000000)
-  - "Area6" if it is connected to Area 6 (0x18000000)
-
-  "Area6" will work for most boards. For ADX, select "Area5".
+  If unsure, say N.
 
 3COM cards
 CONFIG_NET_VENDOR_3COM
@@ -10643,7 +10694,7 @@
   module, say M here and read <file:Documentation/modules.txt> as well
   as <file:Documentation/networking/net-modules.txt>.
 
-EtherExpressPro support/EtherExpress 10 (i82595) support
+EtherExpressPro and EtherExpress 10 (i82595) support
 CONFIG_EEXPRESS_PRO
   If you have a network (Ethernet) card of this type, say Y. This
   driver supports intel i82595{FX,TX} based boards. Note however
@@ -10787,10 +10838,7 @@
   driver and as a module ( = code which can be inserted in and removed
   from the running kernel whenever you want).  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>.
-  If you plan to use more than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
-  <ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini>.  The only
+  as well as <file:Documentation/networking/net-modules.txt>. The only
   currently supported card is the IBM LAN Adapter/A for Ethernet.  It
   will both support 16K and 32K memory windows, however a 32K window
   gives a better security against packet losses.  Usage of multiple
@@ -10914,6 +10962,13 @@
 
   If unsure, say N.
 
+Use PCI shared memory for NIC registers
+CONFIG_TULIP_MMIO
+  Use PCI shared memory for the NIC registers, rather than going through 
+  the Tulip's PIO (programmed I/O ports).  Faster, but could produce 
+  obscure bugs if your mainboard has memory controller timing issues.
+  If in doubt, say N.
+
 Digi Intl. RightSwitch SE-X support
 CONFIG_DGRS
   This is support for the Digi International RightSwitch series of
@@ -10957,7 +11012,7 @@
 CONFIG_FEALNX
   Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet
   cards. Specifications and data at
-  <http:www.myson.com.hk/mtd/datasheet>.
+  <http://www.myson.com.hk/mtd/datasheet/>.
 
 ICL EtherTeam 16i/32 support
 CONFIG_ETH16I
@@ -11001,10 +11056,32 @@
   a module, say M here and read <file:Documentation/modules.txt> as
   well as <file:Documentation/networking/net-modules.txt>.
 
+VIA Rhine MMIO support (EXPERIMENTAL)
+CONFIG_VIA_RHINE_MMIO
+  This instructs the driver to use PCI shared memory (MMIO) instead of
+  programmed I/O ports (PIO). Enabling this gives an improvement in
+  processing time in parts of the driver.
+
+  It is not known if this works reliably on all "rhine" based cards,
+  but it has been tested successfully on some DFE-530TX adapters.
+
+  If unsure, say N.
+
+VIA Rhine MMIO support (EXPERIMENTAL)
+CONFIG_VIA_RHINE_MMIO
+  This instructs the driver to use PCI shared memory (MMIO) instead of
+  programmed I/O ports (PIO). Enabling this gives an improvement in
+  processing time in parts of the driver.
+
+  It is not known if this works reliably on all "rhine" based cards,
+  but it has been tested successfully on some DFE-530TX adapters.
+
+  If unsure, say N.
+
 Davicom DM910x/DM980x support
 CONFIG_DM9102
   This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
-  Davicom (<http://www.davicom.com.tw>).  If you have such a network
+  Davicom (<http://www.davicom.com.tw/>).  If you have such a network
   (Ethernet) card, say Y.  Some information is contained in the file
   <file:Documentation/networking/dmfe.txt>.
 
@@ -11189,8 +11266,7 @@
   Wake On Lan, and PCI 100/16/4 adapters.
 
   If you have such an adapter, say Y and read the Token-Ring
-  mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
+  mini-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).
@@ -11199,15 +11275,14 @@
 
   Also read <file:Documentation/networking/olympic.txt> or check the
   Linux Token Ring Project site for the latest information at
-  <http://www.linuxtr.net>.
+  <http://www.linuxtr.net/>.
 
 IBM Lanstreamer chipset PCI adapter support
 CONFIG_IBMLS
   This is support for IBM Lanstreamer PCI Token Ring Cards.
 
   If you have such an adapter, say Y and read the Token-Ring
-  mini-HOWTO available via FTP (user:anonymous) from
-  <ftp://metalab.unc/edu/pub/Linux/docs/HOWTO>.
+  mini-HOWTO, available from <http://www.linuxdoc.org/docs.html#howto>.
 
   This driver is also available as a modules ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -11358,7 +11433,7 @@
   say Y to "QoS and/or fair queueing" above.
 
   To set up and configure shaper devices, you need the shapecfg
-  program, available from <ftp://shadow.cabi.net/pub/Linux> in the
+  program, available from <ftp://shadow.cabi.net/pub/Linux/> in the
   shaper package.
 
   This driver is also available as a module ( = code which can be
@@ -11619,7 +11694,7 @@
   Say Y here only if you have two CD-ROM controller cards of this type
   (usually only if you have more than four drives).  You should enter
   the parameters for the second, third and fourth interface card into
-  <file:include/linux/sbpcd.h> before compiling the new kernel.  Read
+  <file:drivers/cdrom/sbpcd.h> before compiling the new kernel.  Read
   the file <file:Documentation/cdrom/sbpcd>.
 
 Matsushita/Panasonic, ... third CD-ROM controller support
@@ -11904,7 +11979,7 @@
   <linux-mtd@lists.infradead.org> if you want to help to make it more
   reliable.
 
-Common Flash Interface (CFI) support
+Detect flash chips by Common Flash Interface (CFI) probe
 CONFIG_MTD_CFI
   The Common Flash Interface specification was developed by Intel,
   AMD and other flash manufactures that provides a universal method
@@ -11961,7 +12036,7 @@
   If your flash chips are interleaved in fours - i.e. you have four
   flash chips addressed by each bus cycle, then say 'Y'.
 
-# Choice: mtd_swap_data
+# Choice: mtd_data_swap
 Flash cmd/query data swapping
 CONFIG_MTD_CFI_NOSWAP
   This option defines the way in which the CPU attempts to arrange
@@ -12101,7 +12176,7 @@
   PNC-2000 is the name of Network Camera product from PHOTRON
   Ltd. in Japan. It uses CFI-compliant flash.
 
-Flash chip mapping on RPXlite PPC board
+Flash chip mapping on RPXlite or CLLF PPC board
 CONFIG_MTD_RPXLITE
   The RPXLite PowerPC board has CFI-compliant chips mapped in
   a strange sparse mapping. This 'mapping' driver supports that
@@ -12177,26 +12252,26 @@
   allow a window into the flash.  Both CFI and JEDEC probes are
   called.
 
-Physical start location of flash mapping
+Physical start location of flash chip mapping
 CONFIG_MTD_CSTM_MIPS_IXX_START
   This is the physical memory location that the MTD driver will
   use for the flash chips on your particular target board. 
   Refer to the memory map which should hopefully be in the 
   documentation for your board.
 
-Physical length of flash mapping
+Physical length of flash chip mapping
 CONFIG_MTD_CSTM_MIPS_IXX_LEN
   This is the total length that the MTD driver will use for the 
   flash chips on your particular board.  Refer to the memory
   map which should hopefully be in the documentation for your
   board.
 
-Physical bus width of flash mapping
+Physical bus width of flash mapping in bytes
 CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH
   This is the total bus width of the mapping of the flash chips
   on your particular board.
 
-Flash chip mapping on Mixcom piggyback card
+JEDEC Flash device mapped on Mixcom piggyback card
 CONFIG_MTD_MIXMEM
   This supports the paging arrangement for access to flash chips
   on the MixCOM piggyback card, allowing the flash chip drivers
@@ -12205,14 +12280,14 @@
   you probably want to enable this mapping driver. More info is at
   <http://www.itc.hu/>.
 
-Flash chip mapping on Octagon 5066 SBC
+JEDEC Flash device mapped on Octagon 5066 SBC
 CONFIG_MTD_OCTAGON
   This provides a 'mapping' driver which supports the way in which
   the flash chips are connected in the Octagon-5066 Single Board
   Computer. More information on the board is available at
   <http://www.octagonsystems.com/Products/5066/5066.html>.
 
-Flash chip mapping on Tempustech VMAX SBC301
+JEDEC Flash device mapped on Tempustech VMAX SBC301
 CONFIG_MTD_VMAX
   This provides a 'mapping' driver which supports the way in which
   the flash chips are connected in the Tempustech VMAX SBC301 Single
@@ -12383,7 +12458,7 @@
   allocating space from Linux's available memory. Otherwise, leave 
   this set to zero. Most people will want to leave this as zero.
 
-Flash chip mapping on the Flaga Digital Module
+CFI Flash device mapping on the Flaga Digital Module
 CONFIG_MTD_CFI_FLAGADM
   Mapping for the Flaga digital module.  If you don´t have one, ignore
   this setting.
@@ -12394,6 +12469,100 @@
   NVRAM on the Momenco Ocelot board.  If you have one of these boards
   and would like access to either of these, say 'Y'.
 
+Support for absent chips in bus mapping
+CONFIG_MTD_ABSENT
+  This option enables support for a dummy probing driver used to
+  allocated placeholder MTD devices on systems that have socketed
+  or removable media.  Use of this driver as a fallback chip probe
+  preserves the expected registration order of MTD device nodes on
+  the system regardless of media presence.  Device nodes created
+  with this driver will return -ENODEV upon access.
+
+MTD emulation using block device
+CONFIG_MTD_BLKMTD
+  This driver allows a block device to appear as an MTD. It would
+  generally be used in the following cases:
+
+    Using Compact Flash as an MTD, these usually present themselves to
+    the system as an ATA drive.
+    Testing MTD users (eg JFFS2) on large media and media that might
+    be removed during a write (using the floppy drive).
+
+Cirrus CDB89712 evaluation board mappings
+CONFIG_MTD_CDB89712
+  This enables access to the flash or ROM chips on the CDB89712 board.
+  If you have such a board, say 'Y'.
+
+Detect non-CFI AMD/JEDEC-compatible flash chips
+CONFIG_MTD_JEDECPROBE
+  This option enables JEDEC-style probing of flash chips which are not
+  compatible with the Common Flash Interface, but will use the common
+  CFI-targetted flash drivers for any chips which are identified which
+  are in fact compatible in all but the probe method. This actually
+  covers most AMD/Fujitsu-compatible chips, and will shortly cover also
+  non-CFI Intel chips (that code is in MTD CVS and should shortly be sent
+  for inclusion in Linus' tree)
+
+BIOS flash chip on Intel L440GX boards
+CONFIG_MTD_L440GX
+  Support for treating the BIOS flash chip on Intel L440GX motherboards
+  as an MTD device - with this you can reprogram your BIOS.
+
+  BE VERY CAREFUL.
+
+28F160xx flash driver for LART
+CONFIG_MTD_LART
+  This enables the flash driver for LART. Please note that you do
+  not need any mapping/chip driver for LART. This one does it all
+  for you, so go disable all of those if you enabled some of them (:
+
+Older (theoretically obsoleted now) drivers for non-CFI chips
+CONFIG_MTD_OBSOLETE_CHIPS
+  This option does not enable any code directly, but will allow you to
+  select some other chip drivers which are now considered obsolete,
+  because the generic CONFIG_JEDEC_PROBE code above should now detect
+  the chips which are supported by these drivers, and allow the generic
+  CFI-compatible drivers to drive the chips. Say 'N' here unless you have
+  already tried the CONFIG_JEDEC_PROBE method and reported its failure
+  to the MTD mailing list at <linux-mtd@lists.infradead.org>
+
+CFI Flash device mapped on Hitachi SolutionEngine
+CONFIG_MTD_SOLUTIONENGINE
+  This enables access to the flash chips on the Hitachi SolutionEngine and
+  similar boards. Say 'Y' if you are building a kernel for such a board.
+
+CFI Flash device mapped on TQM8XXL PPC board
+CONFIG_MTD_TQM8XXL
+  The TQM8xxL PowerPC board has up to two banks of CFI-compliant
+  chips, currently uses AMD one. This 'mapping' driver supports
+  that arrangement, allowing the CFI probe and command set driver
+  code to communicate with the chips on the TQM8xxL board. More at
+  <http://www.denx.de/embedded-ppc-en.html>.
+
+Darkness
+CONFIG_MEMORY_SET
+  This is an option about which you will never be asked a question.
+  Therefore, I conclude that you do not exist - go away.
+
+  There is a grue here.
+
+Physical memory size
+CONFIG_MEMORY_SIZE
+  This sets the default memory size assumed by your SH kernel. It can
+  be overridden as normal by the 'mem=' argument on the kernel command
+  line. If unsure, consult your board specifications or just leave it
+  as 0x00400000 which was the default value before this became
+  configurable.
+
+Cache and PCI noncoherent
+CONFIG_SH_PCIDMA_NONCOHERENT
+  Enable this option if your platform does not have a CPU cache which
+  remains coherent with PCI DMA. It is safest to say 'Y', although you
+  will see better performance if you can say 'N', because the PCI DMA
+  code will not have to flush the CPU's caches. If you have a PCI host
+  bridge integrated with your SH CPU, refer carefully to the chip specs
+  to see if you can say 'N' here. Otherwise, leave it as 'Y'.
+
 USB (Universal Serial Bus) support
 CONFIG_USB
   Universal Serial Bus (USB) is a specification for a serial bus
@@ -12438,7 +12607,7 @@
 
   If you have an APC UPS, say Y; otherwise say N.
 
-USB long timeout
+USB long timeout for slow-responding devices (some MGE Ellipse UPSes)
 CONFIG_USB_LONG_TIMEOUT
   This option makes the standard time out a bit longer.  Basically,
   some devices are just slow to respond, so this makes usb more
@@ -12579,7 +12748,7 @@
   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 aiptek.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  module, say M here and read <file:Documentation/modules.txt>.
 
 Use input layer for ADB devices
 CONFIG_INPUT_ADBHID
@@ -12740,7 +12909,7 @@
 CONFIG_USB_SERIAL_VISOR
   Say Y here if you want to connect to your HandSpring Visor, Palm
   m500 or m505 through its USB docking station. See
-  <http://usbvisor.sourceforge.net> for more information on using this
+  <http://usbvisor.sourceforge.net/> for more information on using this
   driver.
 
   This code is also available as a module ( = code which can be
@@ -12776,7 +12945,7 @@
   converter device. The implementation I have is called the USC-1000.
   This driver has also be tested with the 245 and 232 devices.
 
-  See  http://ftdi-usb-sio.sourceforge.net for more
+  See <http://ftdi-usb-sio.sourceforge.net/> for more
   information on this driver and the device.
 
   This code is also available as a module ( = code which can be
@@ -13008,12 +13177,12 @@
   The module will be called ov511.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-USB Communication Class Ethernet driver
+USB Communication Class Ethernet device support
 CONFIG_USB_CDCETHER
   This driver supports devices conforming to the Communication Device
   Class Ethernet Control Model.  This is used in some cable modems.
   For more details on the specification, get the Communication Device
-  Class specification from <http://www.usb.org>.
+  Class specification from <http://www.usb.org/>.
 
   This driver should work with the following devices:
         * Ericsson PipeRider (all variants)
@@ -13077,7 +13246,7 @@
   The module will be called pegasus.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-USB KLSI KL5USB101-based Ethernet device support '
+USB KLSI KL5USB101-based Ethernet device support
 CONFIG_USB_KAWETH
   Say Y here if you want to use one of the following 10Mbps only
   USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
@@ -13140,7 +13309,7 @@
   Say Y here if you want to connect this type of still camera to your
   computer's USB port.  See <file:Documentation/usb/dc2xx.txt> for
   more information; some non-Kodak cameras may also work with this
-  driver, given application support (such as <http://www.gPhoto.org>).
+  driver, given application support (such as <http://www.gphoto.org/>).
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -13151,7 +13320,7 @@
 CONFIG_USB_MDC800
   Say Y here if you want to connect this type of still camera to
   your computer's USB port. This driver can be used with gphoto 0.4.3
-  and higher (look at <http://www.gphoto.org>).
+  and higher (look at <http://www.gphoto.org/>).
   To use it create a device node with "mknod /dev/mustek c 180 32" and
   configure it in your software.
 
@@ -13175,7 +13344,7 @@
   Say Y here in order to have the USB Mass Storage code generate
   verbose debugging messages.
 
-ISD-200 USB/ATA driver
+ISD-200 USB/ATA Bridge support
 CONFIG_USB_STORAGE_ISD200
   Say Y here if you want to use USB Mass Store devices based
   on the In-Systems Design ISD-200 USB/ATA bridge.
@@ -13255,7 +13424,7 @@
 DABUSB driver
 CONFIG_USB_DABUSB
   A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
-  brought to you by the DAB-Team (<http://dab.in.tum.de>).  This
+  brought to you by the DAB-Team (<http://dab.in.tum.de/>).  This
   driver can be taken as an example for URB-based bulk, control, and
   isochronous transactions. URB's are explained in
   <file:Documentation/usb/URB.txt>.
@@ -13295,7 +13464,7 @@
   reader, details at <http://www.microtechint.com/zio/index.html>.
   This driver treats the flash card as a removable storage device.
 
-Sandisk SDDR-09 SmartMedia reader support
+SanDisk SDDR-09 (and other SmartMedia) support
 CONFIG_USB_STORAGE_SDDR09
   Say Y here to include additional code to support the Sandisk SDDR-09
   SmartMedia reader in the USB Mass Storage driver.
@@ -13493,7 +13662,7 @@
   running UML to exchange packets with its host over one of the
   host's Ethertap devices, such as /dev/tap0.  Additional running
   UMLs can use additional Ethertap devices, one per running UML.
-  While the UML believes its on a (multi-device, broadcast) virtual
+  While the UML believes it's on a (multi-device, broadcast) virtual
   Ethernet network, it's in fact communicating over a point-to-point
   link with the host.
 
@@ -13578,7 +13747,7 @@
   and work. SANE 1.0.4 or newer is needed to make use of your scanner.
   This driver can be compiled as a module.
 
-HP 53xx and Minolta Dual Scanner support
+HP53xx and Minolta Dual Scanner support
 CONFIG_USB_HPUSBSCSI
   Say Y here if you want support for the HP 53xx series of scanners
   and the Minolta Scan Dual. This driver is experimental.
@@ -13588,7 +13757,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
+  at <http://developer.axis.com/software/index.shtml>) to fully use
   the device.
 
   This code is also available as a module ( = code which can be
@@ -13617,14 +13786,14 @@
 Reiserfs support
 CONFIG_REISERFS_FS
   Stores not just filenames but the files themselves in a balanced
-  tree.  Uses journaling.
+  tree.  Uses journalling.
 
   Balanced trees are more efficient than traditional file system
   architectural foundations.
 
   In general, ReiserFS is as fast as ext2, but is very efficient with
   large directories and small files.  Additional patches are needed
-  for NFS and quotas, please see <http://www.reiserfs.org> for links.
+  for NFS and quotas, please see <http://www.reiserfs.org/> for links.
 
   It is more easily extended to have features currently found in
   database and keyword search systems than block allocation based file
@@ -13632,7 +13801,7 @@
   plugins consistent with our motto ``It takes more than a license to
   make source code open.''
 
-  Read <http://www.reiserfs.org> to learn more about reiserfs.
+  Read <http://www.reiserfs.org/> to learn more about reiserfs.
 
   Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
 
@@ -13660,15 +13829,6 @@
   everyone but ReiserFS developers and people fine-tuning reiserfs or
   tracing problems should say N.
 
-Publish some reiserfs-specific info under /proc/fs/reiserfs
-CONFIG_REISERFS_PROC_INFO
-  Create under /proc/fs/reiserfs hierarchy of files, displaying
-  various ReiserFS statistics and internal data on the expense of
-  making your kernel or module slightly larger (+8K). This also increases 
-  amount of kernel memory required for each mount. Almost everyone
-  but ReiserFS developers and people fine-tuning reiserfs or tracing
-  problems should say NO.
-
 Second extended fs support
 CONFIG_EXT2_FS
   This is the de facto standard Linux file system (method to organize
@@ -13698,10 +13858,10 @@
   directories on ext2 file systems, use chattr ("man chattr").
 
   Ext2fs partitions can be read from within DOS using the ext2tool
-  command line tool package (available via FTP (user: anonymous) from
-  <ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2>) and from
+  command line tool package (available from
+  <ftp://ibiblio.org/pub/Linux/system/filesystems/ext2/>) and from
   within Windows NT using the ext2nt command line tool package from
-  <ftp://metalab.unc.edu/pub/Linux/utils/dos>.  Explore2fs is a
+  <ftp://ibiblio.org/pub/Linux/utils/dos/>.  Explore2fs is a
   graphical explorer for ext2fs partitions which runs on Windows 95
   and Windows NT and includes experimental write support; it is
   available from
@@ -13715,13 +13875,13 @@
   be compiled as a module, and so this could be dangerous.  Most
   everyone wants to say Y here.
 
-Ext3 journaling file system support (EXPERIMENTAL)
+Ext3 journalling file system support (EXPERIMENTAL)
 CONFIG_EXT3_FS
-  This is the journaling version of the Second extended file system
-  (often called ext3), the de facto standard Linux file system
+  This is the journalling version of the Second extended file system
+  (often called ext2), the de facto standard Linux file system
   (method to organize files on a storage device) for hard disks.
 
-  The journaling code included in this driver means you do not have
+  The journalling code included in this driver means you do not have
   to run e2fsck (file system checker) on your file systems after a
   crash.  The journal keeps track of any changes that were being made
   at the time the system crashed, and can ensure that your file system
@@ -13749,7 +13909,7 @@
 
 Journal Block Device support (JBD for ext3) (EXPERIMENTAL)
 CONFIG_JBD
-  This is a generic journaling layer for block devices.  It is
+  This is a generic journalling layer for block devices.  It is
   currently used by the ext3 file system, but it could also be used to
   add journal support to other file systems or block devices such as
   RAID or LVM.
@@ -13835,9 +13995,14 @@
   mainframe systems.  Only the basic format is supported so far.  If
   you don't know what CMS is you probably don't want to know any more.
 
+# When the 2.5 version of configure.help goes away, the part of this that 
+# duplicates Documentation/filesystems/tmpfs.txt can drop out.
 Virtual memory file system support
 CONFIG_TMPFS
   Tmpfs is a file system which keeps all files in virtual memory.
+  Everything in tmpfs is temporary in the sense that no files will be
+  created on your hard drive. If you reboot, everything in tmpfs will
+  be lost.
 
   In contrast to RAM disks, which get allocated a fixed amount of
   physical RAM, tmpfs grows and shrinks to accommodate the files it
@@ -13864,6 +14029,8 @@
   The initial permissions of the root directory can be set with the
   mount option "mode".
 
+  See <file:Documentation/filesystems/tmpfs.txt> for details.
+
 Simple RAM-based file system support
 CONFIG_RAMFS
   Ramfs is a file system which keeps all files in RAM. It allows
@@ -13901,7 +14068,7 @@
   which allows for long filenames in unicode format (unicode is the
   new 16 bit character code, successor to ASCII, which encodes the
   characters of almost all languages of the world; see
-  <http://www.unicode.org> for more information).  Say Y here if you
+  <http://www.unicode.org/> for more information).  Say Y here if you
   want to be able to read Joliet CD-ROMs under Linux.
 
 Transparent decompression extension
@@ -13986,7 +14153,7 @@
   Linux, you can either use the DOS emulator DOSEMU, described in the
   DOSEMU-HOWTO, available from
   <http://www.linuxdoc.org/docs.html#howto>, or try dmsdosfs in
-  <ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs>. If you
+  <ftp://ibiblio.org/pub/Linux/system/filesystems/dosfs/>. If you
   intend to use dosemu with a non-compressed MSDOS partition, say Y
   here) and MSDOS floppies. This means that file access becomes
   transparent, i.e. the MSDOS files look and behave just like all
@@ -14161,8 +14328,9 @@
   level IP autoconfiguration" above and to "Root file system on NFS"
   below. You cannot compile this driver as a module in this case.
   There are two packages designed for booting diskless machines over
-  the net: netboot and etherboot, both available via FTP from
-  <ftp://metalab.unc.edu/pub/Linux/system/boot/Ethernet/>.
+  the net: netboot, available from
+  <http://ftp1.sourceforge.net/netboot/>, and Etherboot,
+  available from <http://ftp1.sourceforge.net/etherboot/>.
 
   If you don't know what all this is about, say N.
 
@@ -14285,7 +14453,7 @@
   a set of kernel modules that lets you run SCO, Xenix, Wyse,
   UnixWare, Dell Unix and System V programs under Linux.  It is
   available via FTP (user: ftp) from
-  <ftp://ftp.openlinux.org/pub/people/hch/linux-abi>).
+  <ftp://ftp.openlinux.org/pub/people/hch/linux-abi/>).
   NOTE: that will work only for binaries from Intel-based systems;
   PDP ones will have to wait until somebody ports Linux to -11 ;-)
 
@@ -14414,7 +14582,7 @@
   automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
-  <ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4>; you also
+  <ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4/>; you also
   want to answer Y to "NFS file system support", below.
 
   If you want to compile this as a module ( = code which can be
@@ -14445,7 +14613,7 @@
 
 Journalling Flash File System (JFFS) support
 CONFIG_JFFS_FS
-  JFFS is the Journaling Flash File System developed by Axis
+  JFFS is the Journalling Flash File System developed by Axis
   Communications in Sweden, aimed at providing a crash/powerdown-safe
   file system for disk-less embedded devices. Further information is
   available at (<http://developer.axis.com/software/jffs/>).
@@ -14478,6 +14646,11 @@
   If reporting bugs, please try to have available a full dump of the
   messages at debug level 1 while the misbehaviour was occurring.
 
+JFFS stats available in /proc filesystem
+CONFIG_JFFS_PROC_FS
+  Enabling this option will cause statistics from mounted JFFS file systems
+  to be made available to the user in the /proc/fs/jffs/ directory.
+
 UFS file system support (read-only)
 CONFIG_UFS_FS
   BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
@@ -14562,7 +14735,7 @@
   Say Y here if you would like to use hard disks under Linux which
   were partitioned on a Macintosh.
 
-Windows' Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
+Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
 CONFIG_LDM_PARTITION
   Say Y here if you would like to use hard disks under Linux which
   were partitioned using Windows 2000's or XP's Logical Disk Manager.
@@ -14578,11 +14751,11 @@
   XP.
 
   Technical documentation to accompany this driver is available from:
-  <http://linux-ntfs.sf.net/ldm>.
+  <http://linux-ntfs.sf.net/ldm/>.
 
   If unsure, say N.
 
-Windows' LDM extra logging
+Windows LDM extra logging
 CONFIG_LDM_DEBUG
   Say Y here if you would like LDM to log verbosely.  This could be
   helpful if the driver doesn't work as expected and you'd like to
@@ -14706,7 +14879,6 @@
   Note that the experimental "/dev file system support"
   (CONFIG_DEVFS_FS)  is a more general facility.
 
-# This is for Linus's tree
 FreeVxFS file system support (VERITAS VxFS(TM) compatible)
 CONFIG_VXFS_FS
   FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
@@ -14725,25 +14897,6 @@
   module, say M here and read <file:Documentation/modules.txt>.  If
   unsure, say N. 
 
-# This is for Alan's tree.  Note the name difference.
-FreeVxFS file system support (VERITAS VxFS(TM) compatible)
-CONFIG_FREEVXFS_FS
-  FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
-  file system format.  VERITAS VxFS(TM) is the standard file system
-  of SCO UnixWare (and possibly others) and optionally available
-  for Sunsoft Solaris, HP-UX and many other operating systems.
-  Currently only readonly access is supported.
-
-  NOTE: the file system type as used by mount(1), mount(2) and
-        fstab(5) is 'vxfs' as it describes the filesystem format, not
-        the actual driver.
-
-  This file system is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module is called freevxfs.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
 UnixWare slices support
 CONFIG_UNIXWARE_DISKLABEL
   Like some systems, UnixWare uses its own slice table inside a
@@ -14777,8 +14930,8 @@
   Note: if you just want your box to act as an SMB *server* and make
   files and printing services available to Windows clients (which need
   to have a TCP/IP stack), you don't need to say Y here; you can use
-  the program samba (available via FTP (user: anonymous) in
-  <ftp://metalab.unc.edu/pub/Linux/system/network/samba>) for that.
+  the program SAMBA (available from <ftp://ftp.samba.org/pub/samba/>)
+  for that.
 
   General information about how to connect Linux, Windows machines and
   Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
@@ -14827,14 +14980,14 @@
   client and server.  Servers are currently user level, i.e. they need
   no kernel support.  Please read
   <file:Documentation/filesystems/coda.txt> and check out the Coda
-  home page <http://www.coda.cs.cmu.edu>.
+  home page <http://www.coda.cs.cmu.edu/>.
 
   If you want to compile the coda client support 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 coda.o.
 
-InterMezzo file system support (experimental, replicating fs)
+InterMezzo file system support (replicating fs)
 CONFIG_INTERMEZZO_FS
   InterMezzo is a networked file system with disconnected operation
   and kernel level write back caching.  It is most often used for
@@ -14843,7 +14996,7 @@
 
   If you say Y or M your kernel or module will provide InterMezzo
   support.  You will also need a file server daemon, which you can get
-  from <http://www.inter-mezzo.org>.
+  from <http://www.inter-mezzo.org/>.
 
 NCP file system support (to mount NetWare volumes)
 CONFIG_NCP_FS
@@ -15414,6 +15567,7 @@
   Enable Ethernet support via the Motorola MPC8xx serial
   commmunications controller.
 
+# Choice: scc_ethernet
 Ethernet on SCC1
 CONFIG_SCC1_ENET
   Use MPC8xx serial communications controller 1 to drive Ethernet
@@ -15495,7 +15649,7 @@
 CONFIG_ADB_IOP
   The I/O Processor (IOP) is an Apple custom IC designed to provide
   intelligent support for I/O controllers.  It is described at
-  <http://www.angelfire.com/ca2/dev68k/iopdesc.html;> to enable direct
+  <http://www.angelfire.com/ca2/dev68k/iopdesc.html> to enable direct
   support for it, say 'Y' here.
 
 Mac II style Apple Desktop Bus support
@@ -16190,7 +16344,7 @@
   <file:Documentation/modules.txt>.
   The module will be called i2c-dev.o.
 
-I2C /proc support
+I2C /proc interface (required for hardware sensors)
 CONFIG_I2C_PROC
   This provides support for i2c device entries in the /proc filesystem.
   The entries will be found in /proc/sys/dev/sensors.
@@ -16204,9 +16358,7 @@
   Say Y here if your machine has a bus mouse as opposed to a serial
   mouse. Most people have a regular serial MouseSystem or
   Microsoft mouse (made by Logitech) that plugs into a COM port
-  (rectangular with 9 or 25 pins). These people say N here. If you
-  have something else, read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, and say Y here.
+  (rectangular with 9 or 25 pins). These people say N here. 
 
   If you have a laptop, you either have to check the documentation or
   experiment a bit to find out whether the trackball is a serial mouse
@@ -16271,8 +16423,8 @@
   When using a PS/2 mouse, you can get problems if you want to use the
   mouse both on the Linux console and under X. Using the "-R" option
   of the Linux mouse managing program gpm (available from
-  <ftp://metalab.unc.edu/pub/Linux/system/mouse>) solves this
-  problem, or you can get the "mconv2" utility from the same location.
+  <ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
+  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
 
 C&T 82C710 mouse port support (as on TI Travelmate)
 CONFIG_82C710_MOUSE
@@ -16391,7 +16543,7 @@
   Note that the Ftape-HOWTO is out of date (sorry) and documents the
   older version 2.08 of this software but still contains useful
   information.  There is a web page with more recent documentation at
-  <http://www.math1.rwth-aachen.de/~heine/ftape/>.  This page
+  <http://www.instmath.rwth-aachen.de/~heine/ftape/>.  This page
   always contains the latest release of the ftape driver and useful
   information (backup software, ftape related patches and
   documentation, FAQ).  Note that the file system interface has
@@ -16427,7 +16579,7 @@
   file <file:Documentation/ftape.txt> contains a short description of
   the most important changes in the file system interface compared to
   previous versions of ftape.  The ftape home page
-  <http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/> contains
+  <http://www.instmath.rwth-aachen.de/~heine/ftape/> contains
   further information.
 
   IMPORTANT NOTE: zftape can read archives created by previous
@@ -16670,7 +16822,7 @@
   introduced in XFree86 4.0. If you say Y here, you need to select
   the module that's right for your graphics card from the list below.
   These modules provide support for synchronization, security, and
-  DMA transfers. Please see <http://dri.sourceforge.net> for more
+  DMA transfers. Please see <http://dri.sourceforge.net/> for more
   details.  You should also select and configure AGP
   (/dev/agpgart) support.
 
@@ -16925,8 +17077,8 @@
   can be downloaded from:
   <http://developer.intel.com/technology/iapc/acpi/downloads.htm>.
 
-  The ACPI mailing list may also be of interest:
-  <http://phobos.fs.tum.de/acpi/index.html>.
+  The ACPI Sourceforge project may also be of interest:
+  <http://sf.net/projects/acpi/>
 
 Enable ACPI 2.0 with errata 1.3
 CONFIG_ACPI20
@@ -17136,9 +17288,9 @@
   in the kernel source.
 
   The watchdog is usually used together with the watchdog daemon
-  which is available via FTP (user: anonymous) from
-  <ftp://tsx-11.mit.edu/pub/linux/sources/sbin/>. This daemon can also
-  monitor NFS connections and can reboot the machine when the process
+  which is available from
+  <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
+  also monitor NFS connections and can reboot the machine when the process
   table is full.
 
   If unsure, say N.
@@ -17212,7 +17364,7 @@
   and if it does, it reboots your computer after a certain amount of
   time. This driver is like the WDT501 driver but for different
   hardware. Please read <file:Documentation/pcwd-watchdog.txt>. The PC
-  watchdog cards can be ordered from <http://www.berkprod.com>.
+  watchdog cards can be ordered from <http://www.berkprod.com/>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17321,23 +17473,24 @@
   Say Y if you intend to run this kernel on a Toshiba portable.
   Say N otherwise.
 
-Dell Inspiron 8000 support
+Dell laptop support
 CONFIG_I8K
   This adds a driver to safely access the System Management Mode
-  of the CPU on the Dell Inspiron 8000. The System Management Mode
-  is used to read cpu temperature and cooling fan status and to
-  control the fans on the I8K portables.
-
-  This driver has been tested only on the Inspiron 8000 but it may
-  also work with other Dell laptops. You can force loading on other
-  models by passing the parameter `force=1' to the module. Use at
-  your own risk.
-
-  For information on utilities to make use of this driver see the
-  I8K Linux utilities web site at:
-  <http://www.debian.org/~dz/i8k/>
+  of the CPU on the Dell Inspiron and Latitude laptops. The System
+  Management Mode is used to read cpu temperature, cooling fan
+  status and Fn-keys status on Dell laptops. It can also be used
+  to switch the fans on and off.
+
+  The driver has been developed and tested on an Inspiron 8000
+  but it should work on any Dell Inspiron or Latitude laptop.
+  You can force loading on unsupported models by passing the
+  parameter `force=1' to the module. Use at your own risk.
+
+  For more information on this driver and for utilities that make
+  use of the module see the I8K Linux Utilities web site at:
+  <http://www.debian.org/~dz/i8k/>.
 
-  Say Y if you intend to run this kernel on a Dell Inspiron 8000.
+  Say Y if you intend to run this kernel on a Dell laptop.
   Say N otherwise.
 
 /dev/cpu/microcode - Intel IA32 CPU microcode support
@@ -17446,7 +17599,6 @@
   The module will be called nvram.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-# Linus tree only
 Joystick support
 CONFIG_JOYSTICK
   If you have a joystick, 6dof controller, gamepad, steering wheel,
@@ -17454,18 +17606,17 @@
   enable generic support for these controllers. You will also need to
   say Y or M to at least one of the hardware specific drivers. This
   will make the controllers available as /dev/input/jsX devices.
-  Please read the file <file:Documentation/joystick.txt> which
+  Please read the file <file:Documentation/input/joystick.txt> which
   contains more information and the location of the joystick package
   that you'll need.
 
-# AC tree only
 Game port support
 CONFIG_INPUT_GAMEPORT
   Gameport support is for the standard 15-pin PC gameport.  If you
   have a joystick, gamepad, gameport card, a soundcard with a gameport
   or anything else that uses the gameport, say Y or M here and also to
   at least one of the hardware specific drivers.
-  Please read the file <file:Documentation/joystick.txt> which
+  Please read the file <file:Documentation/input/joystick.txt> which
   contains more information and the location of the joystick package
   that you'll need if you use the gameport with a joystick.
 
@@ -17478,7 +17629,7 @@
 CONFIG_INPUT_NS558
   Say Y here if you have an ISA or PnP gameport.
   For more information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17489,7 +17640,7 @@
 CONFIG_INPUT_LIGHTNING
   Say Y here if you have a PDPI Lightning 4 gamecard. For more
   information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17511,7 +17662,7 @@
 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
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17522,7 +17673,7 @@
 CONFIG_INPUT_EMU10K1
   Say Y here if you have a SoundBlaster Live! card and want to use
   its gameport.  For more information on how to use the driver
-  please read <file:Documentation/joystick.txt>.
+  please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17537,7 +17688,7 @@
   additional hats and buttons compatible with CH Flightstick Pro,
   ThrustMaster FCS, 6 and 8 button gamepads, or Saitek Cyborg
   joysticks.  For more information on how to use the driver please
-  read <file:Documentation/joystick.txt>.
+  read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17548,7 +17699,7 @@
 CONFIG_INPUT_A3D
   Say Y here if you have an FPGaming or MadCatz controller using the
   A3D protocol over the PC gameport.  For more information on how to
-  use the driver please read <file:Documentation/joystick.txt>.
+  use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17559,7 +17710,7 @@
 CONFIG_INPUT_ADI
   Say Y here if you have a Logitech controller using the ADI
   protocol over the PC gameport. For more information on how to use
-  the driver please read <file:Documentation/joystick.txt>.
+  the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17570,7 +17721,7 @@
 CONFIG_INPUT_COBRA
   Say Y here if you have a Creative Labs Blaster Cobra gamepad.
   For more information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17581,7 +17732,7 @@
 CONFIG_INPUT_GF2K
   Say Y here if you have a Genius Flight2000 or MaxFighter digitally
   communicating joystick or gamepad.  For more information on how to
-  use the driver please read <file:Documentation/joystick.txt>.
+  use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17592,7 +17743,7 @@
 CONFIG_INPUT_GRIP
   Say Y here if you have a Gravis controller using the GrIP protocol
   over the PC gameport.  For more information on how to use the driver
-  please read <file:Documentation/joystick.txt>.
+  please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17603,7 +17754,7 @@
 CONFIG_INPUT_INTERACT
   Say Y hereif you have an InterAct gameport or joystick
   communicating digitally over the gameport.  For more information on
-  how to use the driver please read <file:Documentation/joystick.txt>.
+  how to use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17615,7 +17766,7 @@
   Say Y here if you have a ThrustMaster controller using the
   DirectConnect (BSP) protocol over the PC gameport.  For more
   information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17626,7 +17777,7 @@
 CONFIG_INPUT_SIDEWINDER
   Say Y here if you have a Microsoft controller using the Digital
   Overdrive protocol over PC gameport.  For more information on how to
-  use the driver please read <file:Documentation/joystick.txt>.
+  use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17638,7 +17789,7 @@
   Say Y here and to the Serial port input line discipline option if
   you plan to use a joystick that communicates over the serial (COM)
   port.  For more information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17649,7 +17800,7 @@
 CONFIG_INPUT_SERPORT
   Say Y here if you plan to use a joystick that communicates over the
   serial (COM) port.  For more information on how to use the driver
-  please read <file:Documentation/joystick.txt>.
+  please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17660,7 +17811,7 @@
 CONFIG_INPUT_WARRIOR
   Say Y here if you have a Logitech WingMan Warrior joystick connected
   to your computer's serial port.  For more information on how to use
-  the driver please read <file:Documentation/joystick.txt>.
+  the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17671,7 +17822,7 @@
 CONFIG_INPUT_MAGELLAN
   Say Y here if you have a Magellan or Space Mouse 6DOF controller
   connected to your computer's serial port.  For more information on
-  how to use the driver please read <file:Documentation/joystick.txt>.
+  how to use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17683,7 +17834,7 @@
   Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
   controller connected to your computer's serial port.  For more
   information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17694,7 +17845,7 @@
 CONFIG_INPUT_SPACEBALL
   Say Y here if you have a SpaceTec SpaceBall 4000 FLX controller
   connected to your computer's serial port.  For more information on
-  how to use the driver please read <file:Documentation/joystick.txt>.
+  how to use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17705,7 +17856,7 @@
 CONFIG_INPUT_STINGER
   Say Y here if you have a Gravis Stinger connected to one of your
   serial ports.  For more information on how to use the driver please
-  read <file:Documentation/joystick.txt>.
+  read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17716,7 +17867,7 @@
 CONFIG_INPUT_IFORCE_232
   Say Y here if you have an I-Force joystick or steering wheel
   connected to your serial (COM) port.  For more information on how
-  to use the driver please read <file:Documentation/joystick.txt>.
+  to use the driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17727,7 +17878,7 @@
 CONFIG_INPUT_IFORCE_USB
   Say Y here if you have an I-Force joystick or steering wheel
   connected to your USB port.  For more information on how to use the
-  driver please read <file:Documentation/joystick.txt>.
+  driver please read <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17740,8 +17891,8 @@
   gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
   Commodore, Amstrad CPC joystick connected to your parallel port.
   For more information on how to use the driver please read
-  <file:Documentation/joystick.txt> and
-  <file:Documentation/joystick-parport.txt>.
+  <file:Documentation/input/joystick.txt> and
+  <file:Documentation/input/joystick-parport.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17755,8 +17906,8 @@
   Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
   Commodore, Amstrad CPC joystick connected to your parallel port.
   For more information on how to use the driver please read
-  <file:Documentation/joystick.txt> and
-  <file:Documentation/joystick-parport.txt>.
+  <file:Documentation/input/joystick.txt> and
+  <file:Documentation/input/joystick-parport.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17768,8 +17919,8 @@
   Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
   and want to use it with Multisystem -- Atari, Amiga, Commodore,
   Amstrad CPC joystick.  For more information on how to use the driver
-  please read <file:Documentation/joystick.txt> and
-  <file:Documentation/joystick-parport.txt>.
+  please read <file:Documentation/input/joystick.txt> and
+  <file:Documentation/input/joystick-parport.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -17780,7 +17931,7 @@
 CONFIG_INPUT_AMIJOY
   Say Y here if you have an Amiga with a digital joystick connected
   to it.  For more information on how to use the driver please read
-  <file:Documentation/joystick.txt>.
+  <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -18353,7 +18504,7 @@
   questions.
 
   Read the <file:Documentation/sound/README.OSS> file and the head of
-  <file:drivers/sound/lowlevel/aedsp16.c> as well as
+  <file:drivers/sound/aedsp16.c> as well as
   <file:Documentation/sound/AudioExcelDSP16> to get more information
   about this driver and its configuration.
 
@@ -18412,12 +18563,20 @@
   or the CMI8378 chipset.  Data on these chips are available at
   <http://www.cmedia.com.tw/>.
 
+  A userspace utility to control some internal registers of these
+  chips is available at
+  <http://member.nifty.ne.jp/Breeze/softwares/unix/cmictl-e.html>.
+
 Support CMI8738 based audio cards
 CONFIG_SOUND_CMPCI_CM8738
   Say Y or M if you have a PCI sound card using the CMI8338
   or the CMI8378 chipset.  Data on this chip is available at
   <http://www.cmedia.com.tw/doc8738.htm>.
 
+  A userspace utility to control some internal registers of these
+  chips is available at
+  <http://member.nifty.ne.jp/Breeze/softwares/unix/cmictl-e.html>.
+
 Enable joystick
 CONFIG_SOUND_CMPCI_JOYSTICK
   Say here in order to enable the joystick port on a sound crd using
@@ -18435,13 +18594,19 @@
   "The 8738 Audio SPDIF In/Out Technical Data" on the technical
   support page at <http://www.cmedia.com.tw/>.
 
+  A userspace utility to control even more internal registers of these
+  chips is available at
+  <http://member.nifty.ne.jp/Breeze/softwares/unix/cmictl-e.html>.
+  This package will among other things help you enable SPDIF 
+  out/in/loop/monitor.
+
 Creative SBLive! (EMU10K1) based PCI sound cards
 CONFIG_SOUND_EMU10K1
   Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
   such as the Creative SBLive!, SB PCI512 or Emu-APS.
 
   For more information on this driver and the degree of support for the
-  different card models please check <http://opensource.creative.com>.
+  different card models please check <http://opensource.creative.com/>.
 
   It is now possible to load dsp microcode patches into the EMU10K1
   chip.  These patches are used to implement real time sound
@@ -18450,7 +18615,7 @@
   Userspace tools to create new patches and load/unload them can be
   found at <http://opensource.creative.com/dist.html>.
 
-Creative EMU10K1 MIDI
+Creative SBLive! (EMU10K1) MIDI
 CONFIG_MIDI_EMU10K1
   Say Y if you want to be able to use the OSS /dev/sequencer
   interface.  This code is still experimental.
@@ -18674,7 +18839,7 @@
 
 Support for ITE 8172G board
 CONFIG_MIPS_ITE8172
-  Ths is an evaluation board made by ITE (http://www.ite.com.tw/)
+  Ths is an evaluation board made by ITE <http://www.ite.com.tw/>
   with ATX form factor that utilizes a MIPS R5000 to work with its
   ITE8172G companion internet appliance chip. The MIPS core can be
   either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build
@@ -18703,20 +18868,21 @@
   website at <http://www.realitydiluted.com/projects/nino/index.html>
   will have more information.
 
-Model-500/510
-CONFIG_NINO_16MB
-  Say Y here to build a kernel specifically for Nino 500/501 color
-  Palm PCs from Philips (INCOMPLETE).
+# Choice: nino_model
+CONFIG_NINO_4MB
+  Say Y here to build a kernel specifically for Nino Palm PCs with
+  4MB of memory. These include models 300/301/302/319.
 
 Model-200/210/312/320/325/350/390
 CONFIG_NINO_8MB
   Say Y here to build a kernel specifically for Nino Palm PCs with
   8MB of memory. These include models 200/210/312/320/325/350/390.
 
+Model-500/510
+CONFIG_NINO_16MB
+  Say Y here to build a kernel specifically for Nino 500/501 color
+  Palm PCs from Philips (INCOMPLETE).
 Model-300/301/302/319
-CONFIG_NINO_4MB
-  Say Y here to build a kernel specifically for Nino Palm PCs with
-  4MB of memory. These include models 300/301/302/319.
 
 Low-level debugging
 CONFIG_LL_DEBUG
@@ -18740,6 +18906,26 @@
   hardware debugging with a logic analyzer and need to see all traffic
   on the bus.
 
+AU1000 serial console
+CONFIG_AU1000_SERIAL_CONSOLE
+  If you have an Alchemy AU1000 processor (MIPS based) and you want
+  to use a console on a serial port, say Y.  Otherwise, say N.
+
+AU1000 serial support
+CONFIG_AU1000_UART
+  If you have an Alchemy AU1000 processor (MIPS based) and you want
+  to use serial ports, say Y.  Otherwise, say N.
+
+AU1000 ethernet controller on SGI MIPS system
+CONFIG_MIPS_AU1000_ENET
+  If you have an Alchemy Semi AU1000 ethernet controller
+  on an SGI MIPS system, say Y.  Otherwise, say N.
+
+WD93 SCSI Controller on SGI MIPS system
+CONFIG_SGIWD93_SCSI
+  If you have a Western Digital WD93 SCSI controller on
+  an SGI MIPS system, say Y.  Otherwise, say N.
+
 Magic System Request Key support
 CONFIG_MAGIC_SYSRQ
   If you say Y here, you will have some control over the system even
@@ -19162,7 +19348,7 @@
   This enables the PCMCIA client driver for the Sedlbauer Speed Star
   and Speed Star II cards.
 
-ST5481 USB ISDN adapter
+ST5481 USB ISDN modem
 CONFIG_HISAX_ST5481
   This enables the driver for ST5481 based USB ISDN adapters,
   e.g. the BeWan Gazel 128 USB
@@ -19188,7 +19374,7 @@
   can be inserted in and removed from the running kernel whenever you
   want, details in <file:Documentation/modules.txt>); the module will
   be called sc.o.  See <file:Documentation/isdn/README.sc> and
-  <http://www.spellcast.com> for more information.
+  <http://www.spellcast.com/> for more information.
 
 Eicon active card support
 CONFIG_ISDN_DRV_EICON
@@ -19330,7 +19516,7 @@
   This enables support for the Auvertech TurboPAM ISDN-card.
   For running this card, additional firmware is necessary, which has
   to be downloaded into the card using a utility which is distributed
-  separately from the Auvertech's web site: <http://www.auvertech.fr>.
+  separately from the Auvertech's web site: <http://www.auvertech.fr/>.
 
   Please redirect all support questions to support@auvertech.fr.
 
@@ -19525,7 +19711,7 @@
   It was designed as a replacement for cables and other short-range
   technologies like IrDA.  Bluetooth operates in personal area range
   that typically extends up to 10 meters.  More information about
-  Bluetooth can be found at <http://www.bluetooth.com>.
+  Bluetooth can be found at <http://www.bluetooth.com/>.
 
   Linux Bluetooth subsystem consist of several layers:
                HCI Core (device and connection manager, scheduler)
@@ -19538,7 +19724,7 @@
   To use Linux Bluetooth subsystem, you will need several user-space
   utilities like hciconfig and hcid.  These utilities and updates to
   Bluetooth kernel modules are provided in the BlueZ package.
-  For more information, see <http://bluez.sf.net>.
+  For more information, see <http://bluez.sourceforge.net/>.
 
   If you want to compile HCI Core as module (hci.o) say M here.
 
@@ -19580,62 +19766,6 @@
 # The following options are for Linux when running on the Hitachi
 # SuperH family of RISC microprocessors.
 
-CPU Selection
-CONFIG_CPU_SUBTYPE_SH7707
-  This is the type of your Hitachi SuperH processor. This information is
-  used for optimizing and configuration purposes.
-
-  - "SH7707" for SH7707
-  - "SH7708" for SH7708, SH7708S, SH7708R
-  - "SH7709" for SH7707, SH7709, SH7709A, and SH7729.
-  - "SH7750" for SH7750, SH7750S
-  - "SH7751" for SH7751
-  - "ST40STB1" for ST40STB1
-
-Target machine selection
-CONFIG_SH_GENERIC
-  This is machine type of your target.
-
-  - "Generic" for Generic kernel which might support all of them
-  - "SolutionEngine" for Hitachi SolutionEngine (7709A, 7750, 7750S)
-  - "SolutionEngine7751" for Hitachi SolutionEngine (7751)
-  - "STB1_Harp" for STMicroelectronics HARP
-  - "STB1_Overdrive" for STMicroelectronics Overdrive
-  - "HP620" for HP 'Jornada' 620
-  - "HP680" for HP 'Jornada' 680
-  - "HP690" for HP 'Jornada' 690
-  - "CqREEK" for CQ Publishing CqREEK SH-4
-  - "DMIDA" for DMIDA, industrial data assistant
-  - "EC3104" for Compaq Aero 8000
-  - "Dreamcast" for SEGA Dreamcast
-  - "CAT68701" for CAT 68701 Evaluation Board (SH7708)
-  - "BigSur" for Big Sur Evaluation Board
-  - "SH2000" for SH2000 Evaluation Board (SH7709A)
-  - "ADX" for A&D ADX
-  - "BareCPU" for Bare CPU board such as CqREEK SH-3
-
-  If unsure, select "BareCPU".
-
-Physical memory start address
-CONFIG_MEMORY_START
-  Computers built with Hitachi SuperH processors always
-  map the ROM starting at address zero.  But the processor
-  does not specify the range that RAM takes.  RAM is usually
-  mapped starting at 0c000000, but it may be elsewhere.
-
-  You should set this value to the address of the lowest
-  RAM location.
-
-  A value of 0c000000 will work for most boards.
-
-Directly Connected Compact Flash support
-CONFIG_CF_ENABLER
-  If your board has "Directly Connected" CompactFlash at area 5 or 6, 
-  you may want to enable this option.  Then, you can use CF as
-  primary IDE drive (only tested for SanDisk).
-
-  If in doubt, press "n".
-
 SuperH RTC support
 CONFIG_SH_RTC
   Selecting this option will allow the Linux kernel to emulate
@@ -19650,38 +19780,7 @@
 
   If unsure, say N.
 
-SuperH SCI (serial) support
-CONFIG_SH_SCI
-  Selecting this option will allow the Linux kernel to transfer
-  data over SCI (Serial Communication Interface) and/or SCIF
-  which are built into the Hitachi SuperH processor.
-
-  If unsure, say N.
-
-Use LinuxSH standard BIOS
-CONFIG_SH_STANDARD_BIOS
-  Say Y here if your target has the gdb-sh-stub package from
-  www.m17n.org (or any conforming standard LinuxSH BIOS) in FLASH
-  or EPROM.  The kernel will use standard BIOS calls during boot
-  for various housekeeping tasks.  Note this does not work with
-  WindowsCE machines.  If unsure, say N.
-
-Early printk support
-CONFIG_SH_EARLY_PRINTK
-  If you say Y here, the kernel printk routine will begin output to
-  the console much earlier in the boot process, before the serial
-  console is initialised, instead of buffering output.  Standard
-  LinuxSH BIOS calls are used for the output.  This helps when
-  debugging fatal problems early in the boot sequence.  This is only
-  useful for kernel hackers.  If unsure, say N.
-  
-National Semiconductor DP83902AV 'ST-NIC' support
-CONFIG_STNIC
-  If you have a network adaptor with National Semiconductor DP83902AV, 
-  say Y or M (for module).
-
-  If unsure, say N.
-
+# Choice: cf_area
 CompactFlash Connection Area
 CONFIG_CF_AREA5
   If your board has "Directly Connected" CompactFlash, You should
@@ -19763,6 +19862,12 @@
   Q60. Select your CPU below.  For 68LC060 don't forget to enable FPU
   emulation.
 
+Q40/Q60 IDE interface support
+CONFIG_BLK_DEV_Q40IDE
+  Enable the on-board IDE controller in the Q40/Q60.  This should
+  normally be on; disable it only if you are running a custom hard
+  drive subsystem through an expansion card.
+
 Sun 3 support
 CONFIG_SUN3
   This option enables support for the Sun 3 series of workstations.
@@ -20371,7 +20476,7 @@
 
   If in doubt, say N.
 
-# Choice: Machine type
+# Choice: ppc4xxtype
 Oak
 CONFIG_OAK
   Select Oak if you have an IBM 403GCX "Oak" Evaluation Board.
@@ -20416,13 +20521,14 @@
 
   If in doubt, say N here.
 
-MPC8xx IDE support
+MPC8xx direct IDE support on PCMCIA port
 CONFIG_BLK_DEV_MPC8xx_IDE
   This option provides support for IDE on Motorola MPC8xx Systems.
   Please see 'Type of MPC8xx IDE interface' for details.
 
   If unsure, say N.
 
+# Choice: mpc8xxtype
 Type of MPC8xx IDE interface
 CONFIG_IDE_8xx_PCCARD
   Select how the IDE devices are connected to the MPC8xx system:
@@ -20483,7 +20589,7 @@
   <http://www.synergymicro.com/PressRel/97_10_15.html>.
 
   Select APUS if configuring for a PowerUP Amiga.  More information is
-  available at: <http://linux-apus.sourceforge.net>.
+  available at: <http://linux-apus.sourceforge.net/>.
 
 Synergy-Gemini
 CONFIG_GEMINI
@@ -20495,124 +20601,9 @@
 CONFIG_APUS
   Select APUS if configuring for a PowerUP Amiga.
   More information is available at:
-  <http://linux-apus.sourceforge.net>.
-
-Embedded 8xx Board Type
-CONFIG_RPXLITE
-  RPX-Lite:
-    Embedded Planet RPX Lite
-
-  RPX-Classic:
-    Embedded Planet RPX Classic Low-fat.
-
-  BSE-IP: 
-    Bright Star Engineering ip-Engine.
-
-  TQM823L:
-  TQM850L:
-  TQM855L:
-  TQM860L:
-    MPC8xx based family of mini modules, half credit card size,
-    up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports,
-    2 x CAN bus interface, ...
-      Manufacturer: TQ Components, www.tq-group.de
-      Date of Release: October (?) 1999
-      End of Life: not yet :-)
-      URL:
-      - module: http://www.denx.de/PDF/TQM8xxLHWM201.pdf
-      - starter kit: http://www.denx.de/PDF/STK8xxLHWM201.pdf
-      - images: http://www.denx.de/embedded-ppc-en.html
+  <http://linux-apus.sourceforge.net/>.
 
-  FPS850L:
-    FingerPrint Sensor System (based on TQM850L)
-      Manufacturer: IKENDI AG, http://www.ikendi.com/
-      Date of Release: November 1999
-      End of life: end 2000 ?
-      URL: see TQM850L
-
-  SPD823TS:
-    MPC823 based board used in the "Tele Server" product
-    Manufacturer: Speech Design, http://www.speech-design.de/
-    Date of Release: Mid 2000 (?)
-    End of life: -
-    URL: http://www.speech-design.de/
-         select "English", then "Teleteam Solutions", then "TeleServer"
-
-  IVMS8:
-    MPC860 based board used in the "Integrated Voice Mail System",
-    Small Version (8 voice channels)
-    Manufacturer: Speech Design, http://www.speech-design.de/
-    Date of Release: December 2000 (?)
-    End of life: -
-    URL: http://www.speech-design.de/
-
-  IVML24:
-    MPC860 based board used in the "Integrated Voice Mail System", 
-    Large Version (24 voice channels)
-    Manufacturer: Speech Design, http://www.speech-design.de/
-    Date of Release: March 2001  (?)
-    End of life: -
-    URL: http://www.speech-design.de/
-
-  SM850:
-    Service Module (based on TQM850L)
-    Manufacturer: Dependable Computer Systems, http://www.decomsys.com/
-    Date of Release: end 2000 (?)
-    End of life: mid 2001 (?)
-    URL: http://www.tz-mikroelektronik.de/ServiceModule/index.html
-
-  HERMES:
-    Hermes-Pro ISDN/LAN router with integrated 8 x hub
-    Manufacturer: Multidata Gesellschaft für Datentechnik und Informatik
-      http://www.multidata.de/
-    Date of Release: 2000 (?)
-    End of life: -
-    URL: http://www.multidata.de/english/products/hpro.htm
-
-  IP860:	
-    VMEBus IP (Industry Pack) carrier board with MPC860
-    Manufacturer: MicroSys GmbH, http://www.microsys.de/
-    Date of Release: ?
-    End of life: -
-    URL: http://www.microsys.de/html/ip860.html
-
-  PCU_E:
-    PCU = Peripheral Controller Unit, Extended
-    Manufacturer: Siemens AG, ICN (Information and Communication Networks)
-    	http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html
-    Date of Release: April 2001
-    End of life: August 2001
-    URL: n. a.
-
-Embedded 82xx Board Type
-CONFIG_EST8260
-  EST8260: Wind River System, Inc. EST SBC8260
-
-  TQM8260:
-    MPC8260 based module, little larger than credit card,
-    up to 128 MB global + 64 MB local RAM, 32 MB Flash,
-    32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet,
-    2 x serial ports, ...
-      Manufacturer: TQ Components, www.tq-group.de
-      Date of Release: June 2001
-      End of Life: not yet :-)
-      URL: http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf
-
-  PM826:
-    Modular system with MPC8260 CPU
-    Manufacturer: MicroSys GmbH, http://www.microsys.de/
-    Date of Release: mid 2001
-    End of life: -
-    URL: http://www.microsys.de/html/pm826.html
-
-  CU824:
-    VMEBus Board with PCI extension with MPC8240 CPU
-    Manufacturer: MicroSys GmbH, http://www.microsys.de/
-    Date of Release: early 2001 (?)
-    End of life: -
-    URL: http://www.microsys.de/html/cu824.html
-
-AltiVec Kernel Support
+AltiVec kernel support
 CONFIG_ALTIVEC
   This option enables kernel support for the Altivec extensions to the
   PowerPC processor. The kernel currently supports saving and restoring
@@ -20684,26 +20675,97 @@
   change the screen brightness.
 
 # Choice: ppc8xxtype
-RPX-Lite
+Embedded 8xx Board Type
 CONFIG_RPXLITE
   Single-board computers based around the PowerPC MPC8xx chips and
   intended for embedded applications.  The following types are
   supported:
 
-    RPX-Lite    -- PC104 form-factor SBC based on the MPC823
-    RPX-Classic -- Credit-card-size SBC based on the MPC 860
-    BSE-IP      -- Bright Star Engineering BSE-IP SBC
-    TQM823L     -- TQM823L SBC from TQ Components
-    TQM850L     -- TQM850L SBC from TQ Components
-    TQM855L     -- TQM855L SBC from TQ Components
-    TQM860L     -- TQM860L SBC from TQ Components
-    FPS850L	-- FingerPrint Sensor from TQ Components
-    TQM860      -- TQM860 SBC from IKENDI AG
-    SPD823TS	-- Speech Design TeleServer from Speech Design
-    IVMS8	-- Integrated VoiceMail SBC from Speech Design
-    SM850       -- Service Module 850 from Dependable Computer Systems
-    MBX         -- MBX821 and MBX860 SBCs
-    Wincept     -- Wincept SBCs for thin-client machines
+  RPX-Lite:
+    Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823.
+
+  RPX-Classic:
+    Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on 
+    the MPC 860
+
+  BSE-IP: 
+    Bright Star Engineering ip-Engine.
+
+  TQM823L:
+  TQM850L:
+  TQM855L:
+  TQM860L:
+    MPC8xx based family of mini modules, half credit card size,
+    up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports,
+    2 x CAN bus interface, ...
+      Manufacturer: TQ Components, www.tq-group.de
+      Date of Release: October (?) 1999
+      End of Life: not yet :-)
+      URL:
+      - module: <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>
+      - starter kit: <http://www.denx.de/PDF/STK8xxLHWM201.pdf>
+      - images: <http://www.denx.de/embedded-ppc-en.html>
+
+  FPS850L:
+    FingerPrint Sensor System (based on TQM850L)
+      Manufacturer: IKENDI AG, <http://www.ikendi.com/>
+      Date of Release: November 1999
+      End of life: end 2000 ?
+      URL: see TQM850L
+
+  SPD823TS:
+    MPC823 based board used in the "Tele Server" product
+    Manufacturer: Speech Design, <http://www.speech-design.de/>
+    Date of Release: Mid 2000 (?)
+    End of life: -
+    URL: <http://www.speech-design.de/>
+         select "English", then "Teleteam Solutions", then "TeleServer"
+
+  IVMS8:
+    MPC860 based board used in the "Integrated Voice Mail System",
+    Small Version (8 voice channels)
+    Manufacturer: Speech Design, <http://www.speech-design.de/>
+    Date of Release: December 2000 (?)
+    End of life: -
+    URL: <http://www.speech-design.de/>
+
+  IVML24:
+    MPC860 based board used in the "Integrated Voice Mail System", 
+    Large Version (24 voice channels)
+    Manufacturer: Speech Design, <http://www.speech-design.de/>
+    Date of Release: March 2001  (?)
+    End of life: -
+    URL: <http://www.speech-design.de/>
+
+  SM850:
+    Service Module (based on TQM850L)
+    Manufacturer: Dependable Computer Systems, <http://www.decomsys.com/>
+    Date of Release: end 2000 (?)
+    End of life: mid 2001 (?)
+    URL: <http://www.tz-mikroelektronik.de/ServiceModule/index.html>
+
+  HERMES:
+    Hermes-Pro ISDN/LAN router with integrated 8 x hub
+    Manufacturer: Multidata Gesellschaft für Datentechnik und Informatik
+      <http://www.multidata.de/>
+    Date of Release: 2000 (?)
+    End of life: -
+    URL: <http://www.multidata.de/english/products/hpro.htm>
+
+  IP860:	
+    VMEBus IP (Industry Pack) carrier board with MPC860
+    Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
+    Date of Release: ?
+    End of life: -
+    URL: <http://www.microsys.de/html/ip860.html>
+
+  PCU_E:
+    PCU = Peripheral Controller Unit, Extended
+    Manufacturer: Siemens AG, ICN (Information and Communication Networks)
+    	<http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html>
+    Date of Release: April 2001
+    End of life: August 2001
+    URL: n. a.
 
 RPX-Classic
 CONFIG_RPXCLASSIC
@@ -20831,7 +20893,7 @@
 #         Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
 #         Date of Release: early 2001 (?)
 #         End of life: -
-#         URL: <http://www.microsys.de/html/cu824.html
+#         URL: <http://www.microsys.de/html/cu824.html>
 #
 # PM826:
 #         Modular system with MPC8260 CPU
@@ -20850,13 +20912,39 @@
 #         End of life: -
 #         URL: n. a.o
 
-Support for EST8260
+# Choice: ppc82xxtype
+Embedded 82xx Board Type
 CONFIG_EST8260
-  The EST8260 is a single-board computer manufactured by Wind River
-  Systems, Inc. (formerly Embedded Support Tools Corp.) and based on
-  the MPC8260.  Wind River Systems has a website at
-  <http://www.windriver.com/>, but the EST8260 cannot be found on it
-  and has probably been discontinued or rebadged.
+  EST8260:
+    The EST8260 is a single-board computer manufactured by Wind River
+    Systems, Inc. (formerly Embedded Support Tools Corp.) and based on
+    the MPC8260.  Wind River Systems has a website at
+    <http://www.windriver.com/>, but the EST8260 cannot be found on it
+    and has probably been discontinued or rebadged.
+
+  TQM8260:
+    MPC8260 based module, little larger than credit card,
+    up to 128 MB global + 64 MB local RAM, 32 MB Flash,
+    32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet,
+    2 x serial ports, ...
+      Manufacturer: TQ Components, www.tq-group.de
+      Date of Release: June 2001
+      End of Life: not yet :-)
+      URL: <http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf>
+
+  PM826:
+    Modular system with MPC8260 CPU
+    Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
+    Date of Release: mid 2001
+    End of life: -
+    URL: <http://www.microsys.de/html/pm826.html>
+
+  CU824:
+    VMEBus Board with PCI extension with MPC8240 CPU
+    Manufacturer: MicroSys GmbH, http://www.microsys.de/
+    Date of Release: early 2001 (?)
+    End of life: -
+    URL: <http://www.microsys.de/html/cu824.html>
 
 ADB raw keycode support
 CONFIG_MAC_ADBKEYCODES
@@ -20870,6 +20958,13 @@
 
   If unsure, say Y here.
 
+I2C/SPI Microcode Patch
+CONFIG_UCODE_PATCH
+  Motorola releases microcode updates for their 8xx CPM modules.  The
+  microcode update file has updates for IIC, SMC and USB.  Currently only
+  the USB update is available by default, if the MPC8xx USB option is
+  enabled.  If in doubt, say 'N' here.
+
 Mouse button 2+3 emulation support
 CONFIG_MAC_EMUMOUSEBTN
   This provides generic support for emulating the 2nd and 3rd mouse
@@ -21013,7 +21108,7 @@
   Support for audio/video capture and overlay devices and FM radio
   cards. The exact capabilities of each device vary. User tools for
   this are available from
-  <ftp://ftp.uk.linux.org/pub/linux/video4linux>.
+  <ftp://ftp.uk.linux.org/pub/linux/video4linux/>.
 
   If you are interested in writing a driver for such an audio/video
   device or user software interacting with such a driver, please read
@@ -21253,7 +21348,7 @@
 Guillemot MAXI Radio FM 2000 Radio Card
 CONFIG_RADIO_MAXIRADIO
   Choose Y here if you have this radio card.  This card may also be
-  found as Gemtek PCI FM.
+  found as GemTek PCI FM.
 
   In order to control your radio card, you will need to use programs
   that are compatible with the Video For Linux API.  Information on
@@ -21284,10 +21379,10 @@
 CONFIG_RADIO_GEMTEK_PORT
   Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
   0x34c, if you haven't changed the jumper setting on the card. On
-  Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
+  Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM GemTek), the I/O
   port is 0x28c.
 
-Gemtek PCI Radio
+GemTek PCI Radio Card support
 CONFIG_RADIO_GEMTEK_PCI
   Choose Y here if you have this PCI FM radio card.
 
@@ -21365,7 +21460,7 @@
   whenever you want). If you want to compile it as a module, say M
   here and read <file:Documentation/modules.txt>.
 
-BT878 Audio DMA
+BT878 audio DMA
 CONFIG_SOUND_BT878
   Audio DMA support for bt878 based grabber boards.  As you might have
   already noticed, bt878 is listed with two functions in /proc/pci.
@@ -21399,7 +21494,7 @@
   Miro DC10 and DC30 video capture cards).
 
 Include support for Iomega Buz
-CONFIG_VIDEO_BUZ
+CONFIG_VIDEO_ZORAN_BUZ
   Say Y here to include support for the Iomega Buz video card.  There
   is a Buz/Linux homepage at <http://www.lysator.liu.se/~gz/buz/>.
 
@@ -21444,7 +21539,7 @@
   as a module (c-qcam.o).
   Read <file:Documentation/video4linux/CQcam.txt> for more information.
 
-Winbond W9966CF Webcam Video For Linux
+W9966 Webcam (FlyCam Supra and others) Video For Linux
 CONFIG_VIDEO_W9966
   Video4linux driver for Winbond's w9966 based Webcams.
   Currently tested with the LifeView FlyCam Supra.
@@ -21452,8 +21547,8 @@
   otherwise say N.
   This driver is also available as a module (w9966.o).
 
-  Check out <file:Documentation/video4linux/w9966.txt> and
-  <file:Documentation/video4linux/w9966.c> for more information.
+  Check out <file:drivers/media/video4linux/w9966.txt> and
+  <file:drivers/media/video/w9966.c> for more information.
 
 CPiA Video For Linux
 CONFIG_VIDEO_CPIA
@@ -21492,7 +21587,7 @@
   it as a module, say M here and read
   <file:Documentation/modules.txt>.
 
-Sony Vaio Picturebook Motion Eye Video for Linux
+Sony Vaio Picturebook Motion Eye Video For Linux
 CONFIG_VIDEO_MEYE
   This is the video4linux driver for the Motion Eye camera found
   in the Vaio Picturebook laptops. Please read the material in
@@ -21555,16 +21650,16 @@
   attached to another IBM mainframe operation system (OS/390, 
   VM/ESA, VSE/ESA).
 
-ECKD devices
+Support for ECKD hard disks
 CONFIG_DASD_ECKD
-  ECKD devices are the most commonly used devices. you should enable
-  this option unless you are very sure to have no ECKD device.
+  ECKD devices are the most commonly used devices. You should enable
+  this option unless you are very sure you have no ECKD device.
 
 CKD devices
 CONFIG_DASD_CKD
   CKD devices are currently unsupported.
 
-FBA devices
+Support for FBA hard disks
 CONFIG_DASD_FBA
   FBA devices are currently unsupported.
 
@@ -21577,25 +21672,23 @@
   CONFIG_IPLABE.
 
 Support for 3215 line mode terminal
-CONFIG_3215
-  Include support for IBM 3215 line-mode terminals.  Can't be used
-  if 3270 console support is chosen.
+CONFIG_TN3215
+  Include support for IBM 3215 line-mode terminals.
 
 Support for console on 3215 line mode terminal
-CONFIG_3215_CONSOLE
-  Include support for using an IBM 3215 line-mode terminal as the
-  Linux system console.  Can't be used if 3270 console support is
-  chosen.
+CONFIG_TN3215_CONSOLE
+  Include support for using an IBM 3215 line-mode terminal as a
+  Linux system console.
 
 Support for 3270 line mode terminal
-CONFIG_3270
+CONFIG_TN3270
   Include support for IBM 3270 line-mode terminals.
 
 Support for console on 3270 line mode terminal
-CONFIG_3270_CONSOLE
-  Include support for using an IBM 3270 line-mode terminal as the
-  Linux system console.  Excludes using 3215s.  Available only if 3270
-  support is compiled in statically.
+CONFIG_TN3270_CONSOLE
+  Include support for using an IBM 3270 line-mode terminal as a Linux
+  system console.  Available only if 3270 support is compiled in
+  statically.
 
 Support for HWC line mode terminal
 CONFIG_HWC
@@ -21846,7 +21939,7 @@
   There are no product plans beyond the current research
   prototypes at this time.  Information is available at:
 
-  <http://crl.research.compaq.com/projects/personalserver>
+  <http://crl.research.compaq.com/projects/personalserver/>
 
   If you have any questions or comments about the  Compaq Personal
   Server, send e-mail to skiff@crl.dec.com.
@@ -21897,6 +21990,12 @@
   Say Y if configuring for an Intrinsyc CerfBoard.
   Say N otherwise.
 
+FlexaNet
+CONFIG_SA1100_FLEXANET
+  Say Y here if you intend to run this kernel on the FlexaNet
+  handheld instruments. Information about this machine can be
+  found at: <http://www.flexanet.com/>.
+
 nanoEngine
 CONFIG_SA1100_NANOENGINE
   The nanoEngine is a StrongARM 1110-based single board computer
@@ -21923,6 +22022,38 @@
   <http://www.visuaide.com/pagevictor.en.html> for information on
   this system.
 
+# Choice: cerf_ram
+Cerf on-board RAM size
+CONFIG_SA1100_CERF_8MB
+   Declare the size of the CerfBoard's on-board RAM.
+   Alternatives are 8, 16, 32, and 64MB.
+
+16MB
+CONFIG_SA1100_CERF_16MB
+   Declare that the CerfBoard has 16MB RAM.
+
+32MB
+CONFIG_SA1100_CERF_32MB
+   Declare that the CerfBoard has 32MB RAM.
+
+64MB
+CONFIG_SA1100_CERF_64MB
+   Declare that the CerfBoard has 64MB RAM.
+
+# Choice: cerf_flash
+Cerf flash memory size
+CONFIG_SA1100_CERF_FLASH_8MB
+  Tell the Cerf kernel the size of on-board memory.  The choices
+  are 8MB, 16MB, or 32MB.
+
+16MB
+CONFIG_SA1100_CERF_FLASH_16MB
+  Configure the Cerf kernel to expect 16MB of flash memory.
+
+32MB
+CONFIG_SA1100_CERF_FLASH_32MB
+  Configure the Cerf kernel to expect 32MB of flash memory.
+
 Support ARM610 processor
 CONFIG_CPU_ARM610
   The ARM610 is the successor to the ARM3 processor
@@ -22284,11 +22415,6 @@
   no management frames, simple fixed header).
   Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1);
 
-IrDA protocol options
-CONFIG_IRDA_OPTIONS
-  Say Y here if you want to configure any of the following IrDA
-  options.
-
 IrDA cache last LSAP
 CONFIG_IRDA_CACHE_LAST_LSAP
   Say Y here if you want IrLMP to cache the last LSAP used.  This
@@ -22300,47 +22426,35 @@
 IrDA Fast RRs
 CONFIG_IRDA_FAST_RR
   Say Y here is you want IrLAP to send fast RR (Receive Ready) frames
-  when acting as a primary station. This will make IrLAP send out a RR
-  frame immediately when receiving a frame if its own transmit queue
-  is currently empty. This will give a lot of speed improvement when
-  receiving much data since the secondary station will not have to
-  wait the max. turn around time before it is allowed to transmit the
-  next time. If the transmit queue of the secondary is also empty the
-  primary will back off waiting longer for sending out the RR frame
-  until the timeout reaches the normal value. Enabling this option
-  will make the IR-diode burn more power and thus reduce your battery
-  life.
+  when acting as a primary station.
+  Disabling this option will make latency over IrDA very bad. Enabling
+  this option will make the IrDA stack send more packet than strictly
+  necessary, thus reduce your battery life (but not that much).
+
+  Fast RR will make IrLAP send out a RR frame immediately when
+  receiving a frame if its own transmit queue is currently empty. This
+  will give a lot of speed improvement when receiving much data since
+  the secondary station will not have to wait the max. turn around
+  time (usually 500ms) before it is allowed to transmit the next time.
+  If the transmit queue of the secondary is also empty, the primary will
+  start backing-off before sending another RR frame, waiting longer
+  each time until the back-off reaches the max. turn around time.
+  This back-off increase in controlled via
+  /proc/sys/net/irda/fast_poll_increase
 
-  If unsure, say N.
+  If unsure, say Y.
 
 IrDA debugging information
 CONFIG_IRDA_DEBUG
   Say Y here if you want the IrDA subsystem to write debug information
   to your syslog. You can change the debug level in
   /proc/sys/net/irda/debug .
+  When this option is enabled, the IrDA also perform many extra internal
+  verifications which will usually prevent the kernel to crash in case of
+  bugs.
 
   If unsure, say Y (since it makes it easier to find the bugs).
 
-IrLAP compression support
-CONFIG_IRDA_COMPRESSION
-  Compression is _not_ part of the IrDA(tm) protocol specification,
-  but it's working great! Linux is the first to try out compression
-  support at the IrLAP layer. This means that you will only benefit
-  from compression if you are running a Linux <-> Linux configuration.
-
-  If you say Y here, you also need to say Y or M to a compression
-  protocol below.
-
-IrLAP Deflate compression
-CONFIG_IRDA_DEFLATE
-  Say Y here if you want to build support for the Deflate compression
-  protocol. The deflate compression (GZIP) is exactly
-  the same as the one used by the PPP protocol.
-
-  If you want to compile this compression support as a module, say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called irda_deflate.o.
-
 IrLAN protocol
 CONFIG_IRLAN
   Say Y here if you want to build support for the IrLAN protocol.  If
@@ -22438,13 +22552,18 @@
   <file:Documentation/modules.txt>.  The module will be called
   nsc-ircc.o.
 
-National Semiconductor DP83820 series driver
+National Semiconductor DP83820 support
 CONFIG_NS83820
   This is a driver for the National Semiconductor DP83820 series
-  of gigabit ethernet MACs.  Cards using this chipset include
-  the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX,
-  SOHO-GA2000T, SOHO-GA2500T.  The driver supports the use of
-  zero copy.
+  of gigabit ethernet MACs.  Cards using this chipset include:
+
+        SMC 9452TX          SMC SMC9462TX       
+        D-Link DGE-500T     PureData PDP8023Z-TG
+        SOHO-GA2000T        SOHO-GA2500T.
+        NetGear GA621
+
+  This driver supports the use of zero copy on tx, checksum 
+  validation on rx, and 64 bit addressing.
 
 Toshiba Type-O IR Port device driver
 CONFIG_TOSHIBA_FIR
@@ -22462,7 +22581,7 @@
   here and read <file:Documentation/modules.txt>.  The module will be
   called smc-ircc.o.
 
-ALi M5123 FIR Controller Driver
+ALi M5123 FIR controller driver
 CONFIG_ALI_FIR
   Say Y here if you want to build support for the ALi M5123 FIR
   Controller.  The ALi M5123 FIR Controller is embedded in ALi M1543C,
@@ -22473,7 +22592,7 @@
   <file:Documentation/modules.txt>.  The module will be called
   ali-ircc.o.
 
-VLSI 82C147 PCI-IrDA Controller Driver
+VLSI 82C147 PCI-IrDA SIR/MIR/FIR Controller driver
 CONFIG_VLSI_FIR
   Say Y here if you want to build support for the VLSI 82C147
   PCI-IrDA Controller. This controller is used by the HP OmniBook 800
@@ -22684,6 +22803,7 @@
 CONFIG_ETRAX_FLASH_BUSWIDTH
   Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
 
+# Choice: crisleds
 LED configuration on PA
 CONFIG_ETRAX_PA_LEDS
   The Etrax network driver is responsible for flashing LED's when
@@ -23168,6 +23288,7 @@
 CONFIG_ETRAX_I2C_EEPROM_8KB
   Use a 8kB EEPROM.
 
+# Choice: etrax_eeprom
 Etrax100 I2C EEPROM (NVRAM) size/probe
 CONFIG_ETRAX_I2C_EEPROM_PROBE
   Specifies size or auto probe of the EEPROM size.
@@ -23215,7 +23336,7 @@
 CONFIG_ETRAX_IDE_CSPE1_16_RESET
   Configures the pin used to reset the IDE bus.
 
-Etrax 100 ATA/IDE support
+Delay for drives to regain consciousness
 CONFIG_ETRAX_IDE_DELAY
   Sets the time to wait for disks to regain consciousness after reset.
 
@@ -23223,6 +23344,7 @@
 CONFIG_ETRAX_IDE_G27_RESET
   Configures the pin used to reset the IDE bus.
 
+# Choice: ide_reset
 IDE reset on PB Bit 7
 CONFIG_ETRAX_IDE_PB7_RESET
   Configures the pin used to reset the IDE bus.
@@ -23541,7 +23663,7 @@
   this.  If in doubt, say Y.
 
 /proc/efi/vars support
-CONFIG_IA64_EFIVARS
+CONFIG_EFI_VARS
   If you say Y here, you are able to get EFI (Extensible Firmware
   Interface) variable information in /proc/efi/vars.  You may read,
   write, create, and destroy EFI variables through this interface.
@@ -23549,6 +23671,42 @@
   To use this option, you have to check that the "/proc file system
   support" (CONFIG_PROC_FS) is enabled, too.
 
+Physical memory granularity (16 MB)
+CONFIG_IA64_GRANULE_16MB
+  IA64 identity-mapped regions use a large page size.  We'll call such
+  large pages "granules".  If you can think of a better name that's
+  unambiguous, let us know...  Unless your identity-mapped regions are
+  very large, select a granule size of 16MB.
+
+Physical memory granularity (64 MB)
+CONFIG_IA64_GRANULE_64MB
+  IA64 identity-mapped regions use a large page size.  We'll call such
+  large pages "granules".  If you can think of a better name that's
+  unambiguous, let us know...  Unless your identity-mapped regions are
+  very large, select a granule size of 16MB.  (This is the "large" choice.)
+
+Enable SGI SN extra debugging code
+CONFIG_IA64_SGI_SN_DEBUG
+  Turns on extra debugging code in the SGI SN (Scalable NUMA) platform
+  for IA64.  Unless you are debugging problems on an SGI SN IA64 box,
+  say N.
+
+Enable SGI Medusa Simulator Support
+CONFIG_IA64_SGI_SN_SIM
+  If you are compiling a kernel that will run under SGI's IA64
+  simulator (Medusa) then say Y, otherwise say N.
+
+PCIBA Support
+CONFIG_PCIBA
+  IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable
+  NUMA) platform for IA64.  Unless you are compiling a kernel for an              SGI SN IA64 box, say N.
+
+Enable protocol mode for the L1 console
+SERIAL_SGI_L1_PROTOCOL
+  Uses protocol mode instead of raw mode for the level 1 console on the
+  SGI SN (Scalable NUMA) platform for IA64.  If you are compiling for
+  an SGI SN box then Y is the recommended value, otherwise say N.
+
 Directly Connected Compact Flash support
 CONFIG_CF_ENABLER
   Compact Flash is a small, removable mass storage device introduced
@@ -23574,7 +23732,7 @@
   allocation as well as poisoning memory on free to catch use of freed
   memory.
 
-Memory mapped I/O debug support
+Memory mapped I/O debugging
 CONFIG_DEBUG_IOVIRT
   Say Y here to get warned whenever an attempt is made to do I/O on
   obviously invalid addresses such as those generated when ioremap()
@@ -23590,6 +23748,19 @@
   best used in conjunction with the NMI watchdog so that spinlock
   deadlocks are also debuggable.
 
+Read-write spinlock debugging
+CONFIG_DEBUG_RWLOCK
+  If you say Y here then read-write lock processing will count how many
+  times it has tried to get the lock and issue an error message after
+  too many attempts.  If you suspect a rwlock problem or a kernel
+  hacker asks for this option then say Y.  Otherwise say N.
+
+Semaphore debugging
+CONFIG_DEBUG_SEMAPHORE
+  If you say Y here then semaphore processing will issue lots of
+  verbose debugging messages.  If you suspect a semaphore problem or a
+  kernel hacker asks for this option then say Y.  Otherwise say N.
+
 Verbose BUG() reporting (adds 70K)
 CONFIG_DEBUG_BUGVERBOSE
   Say Y here to make BUG() panics output the file name and line number
@@ -23698,7 +23869,7 @@
   each of the machines below is described by a machine vector.
 
   Select SolutionEngine if configuring for a Hitachi SH7709
-  or SH7750 evalutation board.
+  or SH7750/7750S evalutation board.
 
   Select Overdrive if configuring for a ST407750 Overdrive board.
   More information at
@@ -23706,34 +23877,43 @@
 
   Select HP620 if configuring for a HP Jornada HP620.
   More information (hardware only) at
-  <http://www.hp.com/jornada>.
+  <http://www.hp.com/jornada/>.
 
   Select HP680 if configuring for a HP Jornada HP680.
   More information (hardware only) at
-  <http://www.hp.com/jornada/products/680>.
+  <http://www.hp.com/jornada/products/680/>.
 
   Select HP690 if configuring for a HP Jornada HP690.
   More information (hardware only) at
-  <http://www.hp.com/jornada/products/680>.
+  <http://www.hp.com/jornada/products/680/>.
 
   Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
   More information at
   <http://sources.redhat.com/ecos/hardware.html#SuperH>.
 
   Select DMIDA if configuring for a DataMyte 4000 Industrial
-  Digital Assistant. More information at <http://www.dmida.com>.
+  Digital Assistant. More information at <http://www.dmida.com/>.
 
   Select EC3104 if configuring for a system with an Eclipse
-  International EC3104 chip, e.g. the Harris AD2000.
+  International EC3104 chip, e.g. the Harris AD2000 or Compaq Aero 8000.
 
   Select Dreamcast if configuring for a SEGA Dreamcast.
   More information at
-  <http://www.m17n.org/linux-sh/dreamcast>.  There is a
+  <http://www.m17n.org/linux-sh/dreamcast/>.  There is a
   Dreamcast project is at <http://linuxdc.sourceforge.net/>.
 
   Select BareCPU if you know what this means, and it applies
   to your system.
 
+# These may have to be merged in when we go to CML2:
+#  - "SolutionEngine7751" for Hitachi SolutionEngine (7751)
+#  - "STB1_Harp" for STMicroelectronics HARP
+#  - "CqREEK" for CQ Publishing CqREEK SH-4
+#  - "CAT68701" for CAT 68701 Evaluation Board (SH7708)
+#  - "BigSur" for Big Sur Evaluation Board
+#  - "SH2000" for SH2000 Evaluation Board (SH7709A)
+#  - "ADX" for A&D ADX
+
 SolutionEngine
 CONFIG_SH_SOLUTION_ENGINE
   Select SolutionEngine if configuring for a Hitachi SH7709
@@ -23754,19 +23934,19 @@
 CONFIG_SH_HP620
   Select HP620 if configuring for a HP jornada HP620.
   More information (hardware only) at
-  <http://www.hp.com/jornada>.
+  <http://www.hp.com/jornada/>.
 
 HP680
 CONFIG_SH_HP680
   Select HP680 if configuring for a HP Jornada HP680.
   More information (hardware only) at
-  <http://www.hp.com/jornada/products/680>.
+  <http://www.hp.com/jornada/products/680/>.
 
 HP690
 CONFIG_SH_HP690
   Select HP690 if configuring for a HP Jornada HP690.
   More information (hardware only)
-  at <http://www.hp.com/jornada/products/680>.
+  at <http://www.hp.com/jornada/products/680/>.
 
 CqREEK
 CONFIG_SH_CQREEK
@@ -23777,7 +23957,7 @@
 DMIDA
 CONFIG_SH_DMIDA
   Select DMIDA if configuring for a DataMyte 4000 Industrial
-  Digital Assistant. More information at <http://www.dmida.com>.
+  Digital Assistant. More information at <http://www.dmida.com/>.
 
 EC3104
 CONFIG_SH_EC3104
@@ -23788,7 +23968,7 @@
 CONFIG_SH_DREAMCAST
   Select Dreamcast if configuring for a SEGA Dreamcast.
   More information at
-  <http://www.m17n.org/linux-sh/dreamcast>.  There is a
+  <http://www.m17n.org/linux-sh/dreamcast/>.  There is a
   Dreamcast project is at <http://linuxdc.sourceforge.net/>.
 
 BareCPU
@@ -23805,7 +23985,8 @@
 # Choice: superhtype
 SH7707
 CONFIG_CPU_SUBTYPE_SH7707
-  Select the type of SuperH processor you have.
+  Select the type of SuperH processor you have. This information is
+  used for optimizing and configuration purposes.
 
   Select SH7707 if you have a  60 Mhz SH-3 HD6417707 CPU.
 
@@ -23816,6 +23997,10 @@
 
   Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
 
+  Select SH7751 if you have a SH7751
+
+  Select ST40STB1 if you have a ST40STB1
+
 SH7708
 CONFIG_CPU_SUBTYPE_SH7708
   Select SH7708 if you have a  60 Mhz SH-3 HD6417708S or
@@ -23831,7 +24016,11 @@
 
 Physical memory start address
 CONFIG_MEMORY_START
-  The physical memory start address will be automatically
+  Computers built with Hitachi SuperH processors always
+  map the ROM starting at address zero.  But the processor
+  does not specify the range that RAM takes.  
+
+  The physical memory (RAM) start address will be automatically
   set to 08000000, unless you selected one of the following
   processor types: SolutionEngine, Overdrive, HP620, HP680, HP690,
   in which case the start address will be set to 0c000000.
@@ -23889,15 +24078,15 @@
   The default setting of the HD64465 IO base address is 0xb0000000.
 
   Do not change this unless you know what you are doing.
-
+  
 Early printk support
 CONFIG_SH_EARLY_PRINTK
-  Say Y here to redirect kernel messages to the serial port
+  Say Y here to redirect kernel printk messages to the serial port
   used by the SH-IPL bootloader, starting very early in the boot
   process and ending when the kernel's serial console is initialised.
   This option is only useful porting the kernel to a new machine,
   when the kernel may crash or hang before the serial console is
-  initialised.
+  initialised. If unsure, say N.
 
 SuperH SCI (serial) support
 CONFIG_SH_SCI
@@ -23951,7 +24140,7 @@
 #
 # This is used by Emacs' spell checker ispell.el:
 #
-# LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
+# LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp ibiblio
 # LocalWords:  unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz
 # LocalWords:  cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd
 # LocalWords:  HD CD-ROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN
@@ -23997,7 +24186,7 @@
 # LocalWords:  bsd comp SPARCstation le SunOS ie Gracilis PackeTwin PT pt LU FX
 # LocalWords:  FX TEAC CR LCS mS ramdisk IDETAPE cmd fperllo encis tcfs unisa
 # LocalWords:  Vertos Genoa Funai hsfs NCP NetWare tgz APM apm ioctls UltraLite
-# LocalWords:  TravelMate CDT LCD backlight VC RPC Mips AXP barlow cdrecord pg
+# LocalWords:  TravelMate CDT LCD backlight VC RPC Mips AXP barlow cdrtools pg
 # LocalWords:  PMAX MILO Alphas Multia Tseng linuxelf endian mipsel mips drv HT
 # LocalWords:  kerneld callouts AdvanSys advansys Admin WDT DataStor EP verden
 # LocalWords:  wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- linux-2.4.16/Documentation/DMA-mapping.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/DMA-mapping.txt	Thu Dec  6 15:47:19 2001
@@ -60,6 +60,9 @@
 might be mapped somewhere entirely different than the rest of physical
 memory.
 
+Also, this means that you cannot take the return of a kmap()
+call and DMA to/from that.  This is similar to vmalloc().
+
 What about block I/O and networking buffers?  The block I/O and
 networking subsystems make sure that the buffers they use are valid
 for you to DMA from/to.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/DocBook/via-audio.tmpl linux/Documentation/DocBook/via-audio.tmpl
--- linux-2.4.16/Documentation/DocBook/via-audio.tmpl	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/DocBook/via-audio.tmpl	Mon Dec 10 18:50:48 2001
@@ -8,11 +8,6 @@
    <author>
     <firstname>Jeff</firstname>
     <surname>Garzik</surname>
-    <affiliation>
-     <address>
-      <email>jgarzik@mandrakesoft.com</email>
-     </address>
-    </affiliation>
    </author>
   </authorgroup>
 
@@ -115,7 +110,7 @@
   <sect1 id="bugrepdiag"><title>Diagnostic output</title>
   <para>
 	Obtain the via-audio-diag diagnostics program from
-	http://gtf.org/garzik/drivers/via82cxxx/ and provide a dump of the
+	http://sf.net/projects/gkernel/ and provide a dump of the
 	audio chip's registers while the problem is occurring.  Sample command line:
   </para>
   <programlisting>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/cachetlb.txt linux/Documentation/cachetlb.txt
--- linux-2.4.16/Documentation/cachetlb.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/cachetlb.txt	Thu Dec  6 15:41:46 2001
@@ -275,7 +275,7 @@
 	for example, uses this technique.
 
 	The "address" parameter tells the virtual address where the
-	user will ultimately this page mapped.
+	user will ultimately have this page mapped.
 
 	If D-cache aliasing is not an issue, these two routines may
 	simply call memcpy/memset directly and do nothing more.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/filesystems/Locking linux/Documentation/filesystems/Locking
--- linux-2.4.16/Documentation/filesystems/Locking	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/filesystems/Locking	Thu Dec  6 20:42:51 2001
@@ -123,6 +123,10 @@
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*bmap)(struct address_space *, long);
+	int (*flushpage) (struct page *, unsigned long);
+	int (*releasepage) (struct page *, int);
+	int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
+
 locking rules:
 	All may block
 		BKL	PageLocked(page)
@@ -132,6 +136,8 @@
 prepare_write:	no	yes
 commit_write:	no	yes
 bmap:		yes
+flushpage:	no	yes
+releasepage:	no	yes
 
 	->prepare_write(), ->commit_write(), ->sync_page() and ->readpage()
 may be called from the request handler (/dev/loop).
@@ -144,6 +150,15 @@
 filesystems and by the swapper. The latter will eventually go away. All
 instances do not actually need the BKL. Please, keep it that way and don't
 breed new callers.
+	->flushpage() is called when the filesystem must attempt to drop
+some or all of the buffers from the page when it is being truncated.  It
+returns zero on success.  If ->flushpage is zero, the kernel uses
+block_flushpage() instead.
+	->releasepage() is called when the kernel is about to try to drop the
+buffers from the page in preparation for freeing it.  It returns zero to
+indicate that the buffers are (or may be) freeable.  If ->flushpage is zero,
+the kernel assumes that the fs has no private interest in the buffers.
+
 	Note: currently almost all instances of address_space methods are
 using BKL for internal serialization and that's one of the worst sources
 of contention. Normally they are calling library functions (in fs/buffer.c)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- linux-2.4.16/Documentation/filesystems/devfs/ChangeLog	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/filesystems/devfs/ChangeLog	Wed Dec  5 20:26:17 2001
@@ -1778,3 +1778,44 @@
   Thanks to Kari Hurtta <hurtta@leija.mh.fmi.fi>
 
 - Avoid deadlock in <devfs_follow_link> by using temporary buffer
+===============================================================================
+Changes for patch v197
+
+- First release of new locking code for devfs core (v1.0)
+
+- Fixed bug in drivers/cdrom/cdrom.c
+===============================================================================
+Changes for patch v198
+
+- Discard temporary buffer, now use "%s" for dentry names
+
+- Don't generate path in <try_modload>: use fake entry instead
+
+- Use "existing" directory in <_devfs_make_parent_for_leaf>
+
+- Use slab cache rather than fixed buffer for devfsd events
+===============================================================================
+Changes for patch v199
+
+- Removed obsolete usage of DEVFS_FL_NO_PERSISTENCE
+
+- Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>
+
+- Fixed locking bug in <devfs_d_revalidate_wait> due to typo
+
+- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd
+  or children
+===============================================================================
+Changes for patch v199.1
+
+- Fixed bug in <devfsd_read>: was dereferencing freed pointer
+===============================================================================
+Changes for patch v199.2
+
+- Fixed bug in <devfsd_close>: was dereferencing freed pointer
+
+- Added process group check for devfsd privileges
+===============================================================================
+Changes for patch v199.3
+
+- Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- linux-2.4.16/Documentation/filesystems/devfs/README	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/filesystems/devfs/README	Tue Dec  4 19:25:30 2001
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-29-SEP-2001
+9-NOV-2001
 
 -----------------------------------------------------------------------------
 
@@ -11,7 +11,9 @@
 
 http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
 and looks much better than the text version distributed with the
-kernel sources.
+kernel sources. A mirror site is available at:
+
+http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html
 
 There is also an optional daemon that may be used with devfs. You can
 find out more about it at:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/filesystems/tmpfs.txt linux/Documentation/filesystems/tmpfs.txt
--- linux-2.4.16/Documentation/filesystems/tmpfs.txt	Thu Jan  1 00:00:00 1970
+++ linux/Documentation/filesystems/tmpfs.txt	Thu Dec  6 16:13:26 2001
@@ -0,0 +1,102 @@
+Tmpfs is a file system which keeps all files in virtual memory.
+
+
+Everything in tmpfs is temporary in the sense that no files will be
+created on your hard drive. If you unmount a tmpfs instance,
+everything stored therein is lost.
+
+tmpfs puts everything into the kernel internal caches and grows and
+shrinks to accommodate the files it contains and is able to swap
+unneeded pages out to swap space. It has maximum size limits which can
+be adjusted on the fly via 'mount -o remount ...'
+
+If you compare it to ramfs (which was the template to create tmpfs)
+you gain swapping and limit checking. Another similar thing is the RAM
+disk (/dev/ram*), which simulates a fixed size hard disk in physical
+RAM, where you have to create an ordinary filesystem on top. Ramdisks
+cannot swap and you do not have the possibility to resize them. 
+
+Since tmpfs lives completely in the page cache and on swap, all tmpfs
+pages currently in memory will show up as cached. It will not show up
+as shared or something like that. Further on you can check the actual
+RAM+swap use of a tmpfs instance with df(1) and du(1).
+
+
+tmpfs has the following uses:
+
+1) There is always a kernel internal mount which you will not see at
+   all. This is used for shared anonymous mappings and SYSV shared
+   memory. 
+
+   This mount does not depend on CONFIG_TMPFS. If CONFIG_TMPFS is not
+   set, the user visible part of tmpfs is not build. But the internal
+   mechanisms are always present.
+
+2) glibc 2.2 and above expects tmpfs to be mounted at /dev/shm for
+   POSIX shared memory (shm_open, shm_unlink). Adding the following
+   line to /etc/fstab should take care of this:
+
+	tmpfs	/dev/shm	tmpfs	defaults	0 0
+
+   Remember to create the directory that you intend to mount tmpfs on
+   if necessary (/dev/shm is automagically created if you use devfs).
+
+   This mount is _not_ needed for SYSV shared memory. The internal
+   mount is used for that. (In the 2.3 kernel versions it was
+   necessary to mount the predecessor of tmpfs (shm fs) to use SYSV
+   shared memory)
+
+3) Some people (including me) find it very convenient to mount it
+   e.g. on /tmp and /var/tmp and have a big swap partition. But be
+   aware: loop mounts of tmpfs files do not work due to the internal
+   design. So mkinitrd shipped by most distributions will fail with a
+   tmpfs /tmp.
+
+4) And probably a lot more I do not know about :-)
+
+
+tmpfs has a couple of mount options:
+
+size:	   The limit of allocated bytes for this tmpfs instance. The 
+           default is half of your physical RAM without swap. If you
+	   oversize your tmpfs instances the machine will deadlock
+	   since the OOM handler will not be able to free that memory.
+nr_blocks: The same as size, but in blocks of PAGECACHE_SIZE.
+nr_inodes: The maximum number of inodes for this instance. The default
+           is half of the number of your physical RAM pages.
+
+These parameters accept a suffix k, m or g for kilo, mega and giga and
+can be changed on remount.
+
+To specify the initial root directory you can use the following mount
+options:
+
+mode:	The permissions as an octal number
+uid:	The user id 
+gid:	The group id
+
+These options do not have any effect on remount. You can change these
+parameters with chmod(1), chown(1) and chgrp(1) on a mounted filesystem.
+
+
+So 'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs'
+will give you tmpfs instance on /mytmpfs which can allocate 10GB
+RAM/SWAP in 10240 inodes and it is only accessible by root.
+
+
+TODOs:
+
+1) give the size option a percent semantic: If you give a mount option
+   size=50% the tmpfs instance should be able to grow to 50 percent of
+   RAM + swap. So the instance should adapt automatically if you add
+   or remove swap space.
+2) loop mounts: This is difficult since loop.c relies on the readpage
+   operation. This operation gets a page from the caller to be filled
+   with the content of the file at that position. But tmpfs always has
+   the page and thus cannot copy the content to the given page. So it
+   cannot provide this operation. The VM had to be changed seriously
+   to achieve this.
+3) Show the number of tmpfs RAM pages. (As shared?)
+
+Author:
+   Christoph Rohland <cr@sap.com>, 1.12.01
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE
--- linux-2.4.16/Documentation/isdn/INTERFACE	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/INTERFACE	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.15.8.2 2001/03/13 16:17:07 kai Exp $
+$Id: INTERFACE,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/INTERFACE.fax linux/Documentation/isdn/INTERFACE.fax
--- linux-2.4.16/Documentation/isdn/INTERFACE.fax	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/INTERFACE.fax	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: INTERFACE.fax,v 1.2 2000/08/06 09:22:50 armin Exp $
+$Id: INTERFACE.fax,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 
 
 Description of the fax-subinterface between linklevel and hardwarelevel of 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/README.act2000 linux/Documentation/isdn/README.act2000
--- linux-2.4.16/Documentation/isdn/README.act2000	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/README.act2000	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $
+$Id: README.act2000,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 
 This document describes the ACT2000 driver for the
 IBM Active 2000 ISDN card.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/README.audio linux/Documentation/isdn/README.audio
--- linux-2.4.16/Documentation/isdn/README.audio	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/README.audio	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: README.audio,v 1.8 1999/07/11 17:17:29 armin Exp $
+$Id: README.audio,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 
 ISDN subsystem for Linux.
   Description of audio mode.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon
--- linux-2.4.16/Documentation/isdn/README.eicon	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/README.eicon	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: README.eicon,v 1.10.6.1 2001/02/19 10:04:59 armin Exp $
+$Id: README.eicon,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 
 (c) 1999,2000 Armin Schindler (mac@melware.de)
 (c) 1999,2000 Cytronics & Melware (info@melware.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/README.hysdn linux/Documentation/isdn/README.hysdn
--- linux-2.4.16/Documentation/isdn/README.hysdn	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/README.hysdn	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $
+$Id: README.hysdn,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 The hysdn driver has been written by
 by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) 
 for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/isdn/README.icn linux/Documentation/isdn/README.icn
--- linux-2.4.16/Documentation/isdn/README.icn	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/isdn/README.icn	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
+$Id: README.icn,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
 
 You can get the ICN-ISDN-card from:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt
--- linux-2.4.16/Documentation/networking/decnet.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/networking/decnet.txt	Thu Dec  6 15:47:36 2001
@@ -4,20 +4,9 @@
 1) Other documentation....
 
    o Project Home Pages
-       http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html - Kernel info
+       http://www.chygwyn.com/DECnet/                      - Kernel info
        http://linux-decnet.sourceforge.net/                - Userland tools
-
-   o FTP sites
-       ftp://ftp.sucs.swan.ac.uk/pub/Linux/DECnet/
-                - Swansea University Computer Society DECnet Archive
-                  (contains kernel patches and info)
-                - Mirror of userland tools on ftp.dreamtime.org
-                - Mirror of Alexey Kuznetsov's iproute2 package and
-                  other utilities
-
-       ftp://linux-decnet.sourceforge.net/pub/linux-decnet/ 
-                - Patrick Caulfield's archive of userland tools and
-                  Eduardo Serrat's kernel patches
+       http://www.sourceforge.net/projects/linux-decnet/   - Status page
 
 2) Configuring the kernel
 
@@ -31,9 +20,13 @@
 you'll need the following options as well...
 
     CONFIG_DECNET_ROUTER (to be able to add/delete routes)
-    CONFIG_NETLINK (to allow rtnetlink)
-    CONFIG_RTNETLINK (for communication with the kernel routing layer)
     CONFIG_NETFILTER (will be required for the DECnet routing daemon)
+
+    CONFIG_DECNET_ROUTE_FWMARK is optional
+
+Don't turn on SIOCGIFCONF support for DECnet unless you are really sure
+that you need it, in general you won't and it can cause ifconfig to
+malfunction.
 
 3) Command line options
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt
--- linux-2.4.16/Documentation/networking/tulip.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/networking/tulip.txt	Thu Jan  1 00:00:00 1970
@@ -1,226 +0,0 @@
-                Tulip Ethernet Card Driver
-	  Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-
-The Tulip driver was developed by Donald Becker and changed by
-Takashi Manabe and a cast of thousands.
-
-For 2.4.x and later kernels, the Linux Tulip driver is available at
-http://sourceforge.net/projects/tulip/
-
-	This driver is for the Digital "Tulip" Ethernet adapter interface.
-	It should work with most DEC 21*4*-based chips/ethercards, as well as
-	with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
-	Additional information on Donald Becker's tulip.c
-	is available at http://www.scyld.com/network/tulip.html
-
-
-
-
-				Theory of Operation
-
-Board Compatibility
-===================
-
-This device driver is designed for the DECchip "Tulip", Digital's
-single-chip ethernet controllers for PCI.  Supported members of the family
-are the 21040, 21041, 21140, 21140A, 21142, and 21143.  Similar work-alike
-chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
-supported.
-
-These chips are used on at least 140 unique PCI board designs.  The great
-number of chips and board designs supported is the reason for the
-driver size and complexity.  Almost of the increasing complexity is in the
-board configuration and media selection code.  There is very little
-increasing in the operational critical path length.
-
-Board-specific settings
-=======================
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS preferably should assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-Some boards have EEPROMs tables with default media entry.  The factory default
-is usually "autoselect".  This should only be overridden when using
-transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
-for forcing full-duplex when used with old link partners that do not do
-autonegotiation.
-
-Driver operation
-================
-
-Ring buffers
-------------
-
-The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
-This driver uses statically allocated rings of Rx and Tx descriptors, set at
-compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
-for the Rx ring buffers at open() time and passes the skb->data field to the
-Tulip as receive data buffers.  When an incoming frame is less than
-RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
-copied to the new skbuff.  When the incoming frame is larger, the skbuff is
-passed directly up the protocol stack and replaced by a newly allocated
-skbuff.
-
-The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-using a full-sized skbuff for small frames vs. the copying costs of larger
-frames.  For small frames the copying cost is negligible (esp. considering
-that we are pre-loading the cache with immediately useful header
-information).  For large frames the copying cost is non-trivial, and the
-larger copy might flush the cache of useful data.  A subtle aspect of this
-choice is that the Tulip only receives into longword aligned buffers, thus
-the IP header at offset 14 isn't longword aligned for further processing.
-Copied frames are put into the new skbuff at an offset of "+2", thus copying
-has the beneficial effect of aligning the IP header and preloading the
-cache.
-
-Synchronization
----------------
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-The send packet thread has partial control over the Tx ring and '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 'tp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
-we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-stats.)	 After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-
-Notes
-=====
-
-Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
-Greg LaPolla at Linksys provided PNIC and other Linksys boards.
-Znyx provided a four-port card for testing.
-
-References
-==========
-
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-http://www.digital.com  (search for current 21*4* datasheets and "21X4 SROM")
-http://www.national.com/pf/DP/DP83840A.html
-http://www.asix.com.tw/pmac.htm
-http://www.admtek.com.tw/
-
-Errata
-======
-
-The old DEC databooks were light on details.
-The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written.  Hmmm, now how is that possible?
-
-The DEC SROM format is very badly designed not precisely defined, leading to
-part of the media selection junkheap below.  Some boards do not have EEPROM
-media tables and need to be patched up.  Worse, other boards use the DEC
-design kit media table when it isn't correct for their board.
-
-We cannot use MII interrupts because there is no defined GPIO pin to attach
-them.  The MII transceiver status is polled using an kernel timer.
-
-
-Source tree tour
-================
-The following is a list of files comprising the Tulip ethernet driver in
-drivers/net/tulip subdirectory.
-
-21142.c		- 21142-specific h/w interaction
-eeprom.c	- EEPROM reading and parsing
-interrupt.c	- Interrupt handler
-media.c		- Media selection and MII support
-pnic.c		- PNIC-specific h/w interaction
-timer.c		- Main driver timer, and misc h/w timers
-tulip.h		- Private driver header
-tulip_core.c	- Driver core (a.k.a. where "everything else" goes)
-
-
-
-Version history
-===============
-0.9.14 (February 20, 2000):
-* Fix PNIC problems (Manfred Spraul)
-* Add new PCI id for Accton comet
-* Support Davicom tulips
-* Fix oops in eeprom parsing
-* Enable workarounds for early PCI chipsets
-* IA64, hppa csr0 support
-* Support media types 5, 6
-* Interpret a bit more of the 21142 SROM extended media type 3
-* Add missing delay in eeprom reading
-
-0.9.11 (November 3, 2000):
-* Eliminate extra bus accesses when sharing interrupts (prumpf)
-* Barrier following ownership descriptor bit flip (prumpf)
-* Endianness fixes for >14 addresses in setup frames (prumpf)
-* Report link beat to kernel/userspace via netif_carrier_*. (kuznet)
-* Better spinlocking in set_rx_mode.
-* Fix I/O resource request failure error messages (DaveM catch)
-* Handle DMA allocation failure.
-
-0.9.10 (September 6, 2000):
-* Simple interrupt mitigation (via jamal)
-* More PCI ids
-
-0.9.9 (August 11, 2000):
-* More PCI ids
-
-0.9.8 (July 13, 2000):
-* Correct signed/unsigned comparison for dummy frame index
-* Remove outdated references to struct enet_statistics
-
-0.9.7 (June 17, 2000):
-* Timer cleanups (Andrew Morton)
-* Alpha compile fix (somebody?)
-
-0.9.6 (May 31, 2000):
-* Revert 21143-related support flag patch
-* Add HPPA/media-table debugging printk
-
-0.9.5 (May 30, 2000):
-* HPPA support (willy@puffingroup)
-* CSR6 bits and tulip.h cleanup (Chris Smith)
-* Improve debugging messages a bit
-* Add delay after CSR13 write in t21142_start_nway
-* Remove unused ETHER_STATS code
-* Convert 'extern inline' to 'static inline' in tulip.h (Chris Smith)
-* Update DS21143 support flags in tulip_chip_info[]
-* Use spin_lock_irq, not _irqsave/restore, in tulip_start_xmit()
-* Add locking to set_rx_mode()
-* Fix race with chip setting DescOwned bit (Hal Murray)
-* Request 100% of PIO and MMIO resource space assigned to card
-* Remove error message from pci_enable_device failure
-
-0.9.4.3 (April 14, 2000):
-* mod_timer fix (Hal Murray)
-* PNIC2 resuscitation (Chris Smith)
-
-0.9.4.2 (March 21, 2000):
-* Fix 21041 CSR7, CSR13/14/15 handling
-* Merge some PCI ids from tulip 0.91x
-* Merge some HAS_xxx flags and flag settings from tulip 0.91x
-* asm/io.h fix (submitted by many) and cleanup
-* s/HAS_NWAY143/HAS_NWAY/
-* Cleanup 21041 mode reporting
-* Small code cleanups
-
-0.9.4.1 (March 18, 2000):
-* Finish PCI DMA conversion (davem)
-* Do not netif_start_queue() at end of tulip_tx_timeout() (kuznet)
-* PCI DMA fix (kuznet)
-* eeprom.c code cleanup
-* Remove Xircom Tulip crud
-
-
-[EOF]
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/pci.txt linux/Documentation/pci.txt
--- linux-2.4.16/Documentation/pci.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/pci.txt	Fri Dec  7 18:08:43 2001
@@ -104,6 +104,10 @@
 	If you are sure the driver is not a hotplug driver then use only 
 	__init/exit __initdata/exitdata.
 
+        Pointers to functions marked as __devexit must be created using
+        __devexit_p(function_name).  That will generate the function
+        name or NULL if the __devexit function will be discarded.
+
 
 2. How to find PCI devices manually (the old style)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/pm.txt linux/Documentation/pm.txt
--- linux-2.4.16/Documentation/pm.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/pm.txt	Tue Dec  4 19:25:30 2001
@@ -34,7 +34,7 @@
 system the associated daemon will exit gracefully.
 
   apmd:   http://worldvisions.ca/~apenwarr/apmd/
-  acpid:  http://phobos.fs.tum.de/acpi/
+  acpid:  http://acpid.sf.net/
 
 Driver Interface
 ----------------
@@ -260,7 +260,7 @@
 Q: Who do I contact for additional information about
    enabling power management for my specific driver/device?
 
-ACPI4Linux mailing list: acpi@phobos.fs.tum.de
+ACPI Development mailing list: acpi-devel@lists.sourceforge.net
 
 System Interface
 ----------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/sonypi.txt linux/Documentation/sonypi.txt
--- linux-2.4.16/Documentation/sonypi.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/sonypi.txt	Fri Dec  7 19:17:35 2001
@@ -58,6 +58,10 @@
 			get enabled unless you set this parameter to 1.
 			Do not use this option unless it's actually necessary,
 			some Vaio models don't deal well with this option.
+			This option is available only if the kernel is 
+			compiled without ACPI support (since it conflicts
+			with it and it shouldn't be required anyway if 
+			ACPI is already enabled).
 
 	verbose:	print unknown events from the sonypi device
 
@@ -93,7 +97,10 @@
 	- some users reported that the laptop speed is lower (dhrystone
 	  tested) when using the driver with the fnkeyinit parameter. I cannot
 	  reproduce it on my laptop and not all users have this problem.
-	  Still under investigation.
+	  This happens because the fnkeyinit parameter enables the ACPI 
+	  mode (but without additionnal ACPI control, like processor 
+	  speed handling etc). Use ACPI instead of APM if it works on your
+	  laptop.
 	
 	- since all development was done by reverse engineering, there is
 	  _absolutely no guarantee_ that this driver will not crash your
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt
--- linux-2.4.16/Documentation/usb/philips.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/usb/philips.txt	Tue Dec  4 19:25:30 2001
@@ -1,5 +1,5 @@
 This file contains some additional information for the Philips webcams.
-E-mail: webcam@smcc.demon.nl                        Last updated: 2001-07-27
+E-mail: webcam@smcc.demon.nl                        Last updated: 2001-09-24
 
 The main webpage for the Philips driver is http://www.smcc.demon.nl/webcam/.
 It contains a lot of extra information, a FAQ, and the binary plugin
@@ -13,11 +13,9 @@
 the latter, since it makes troubleshooting a lot easier. The built-in
 microphone is supported through the USB Audio class.
 
-(Taken from install.html)
-
 When you load the module you can set some default settings for the
-camera; some programs depend on a particular image-size or -format. The
-options are:
+camera; some programs depend on a particular image-size or -format and
+don't know how to set it properly in the driver. The options are:
 
 size
    Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
@@ -99,6 +97,57 @@
    This parameter works only with the ToUCam range of cameras (730, 740,
    750). For other cameras this command is silently ignored, and the LED
    cannot be controlled.
+
+dev_hint
+   A long standing problem with USB devices is their dynamic nature: you
+   never know what device a camera gets assigned; it depends on module load
+   order, the hub configuration, the order in which devices are plugged in,
+   and the phase of the moon (i.e. it can be random). With this option you
+   can give the driver a hint as to what video device node (/dev/videoX) it
+   should use with a specific camera. This is also handy if you have two
+   cameras of the same model.
+
+   A camera is specified by its type (the number from the camera model,
+   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
+   in /proc/bus/usb/devices). A hint consists of a string with the following
+   format:
+
+      [type[.serialnumber]:]node
+      
+   The square brackets mean that both the type and the serialnumber are
+   optional, but a serialnumber cannot be specified without a type (which
+   would be rather pointless). The serialnumber is separated from the type
+   by a '.'; the node number by a ':'.
+   
+   This somewhat cryptic syntax is best explained by a few examples:
+
+     dev_hint=3,5              The first detected cam gets assigned
+                               /dev/video3, the second /dev/video5. Any
+                               other cameras will get the first free 
+                               available slot (see below).
+
+     dev_hint=645:1,680=2      The PCA645 camera will get /dev/video1,
+                               and a PCVC680 /dev/video2.
+                               
+     dev_hint=645.0123:3,645.4567:0	The PCA645 camera with serialnumber 
+                                        0123 goes to /dev/video3, the same
+                                        camera model with the 4567 serial
+                                        gets /dev/video0.
+
+     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the 
+                                next 3 Philips cams will use /dev/video4 
+                                through /dev/video6.
+
+   Some points worth knowing:
+   - Serialnumbers are case sensitive and must be written full, including 
+     leading zeroes (it's treated as a string).
+   - If a device node is already occupied, registration will fail and 
+     the webcam is not available.
+   - You can have up to 64 video devices; be sure to make enough device
+     nodes in /dev if you want to spread the numbers (this does not apply
+     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
+   - If a camera does not match any dev_hint, it will simply get assigned
+     the first available device node, just as it used to be.
 
 trace
    In order to better detect problems, it is now possible to turn on a
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt
--- linux-2.4.16/Documentation/usb/scanner.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/usb/scanner.txt	Tue Dec  4 19:25:30 2001
@@ -83,7 +83,7 @@
 	`mknod /dev/usbscanner1 c 180 49`
                       . 
                       .
-	`mknod /dev/usbscanner15 180 63`
+	`mknod /dev/usbscanner15 c 180 63`
 
 
 If you foresee using only one scanner it is best to:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/video4linux/Zoran linux/Documentation/video4linux/Zoran
--- linux-2.4.16/Documentation/video4linux/Zoran	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/video4linux/Zoran	Tue Dec  4 19:25:30 2001
@@ -160,9 +160,9 @@
   set aside the necessary memory during boot time. There seem to be
   several versions of this patch against various kernel versions
   floating around in the net, you may obtain one e.g. from:
-  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You
-  also have to compile your driver AFTER installing that patch in order
-  to get it working
+  http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea
+  You also have to compile your driver AFTER installing that patch in
+  order to get it working
 
   or
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Documentation/video4linux/w9966.txt linux/Documentation/video4linux/w9966.txt
--- linux-2.4.16/Documentation/video4linux/w9966.txt	Mon Nov 26 10:35:04 2001
+++ linux/Documentation/video4linux/w9966.txt	Tue Dec  4 19:25:30 2001
@@ -1,37 +1,33 @@
+W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com)
 
-W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se)
+After a lot of work in softice & wdasm, reading .pdf-files and tiresome
+trial-and-error work I've finally got everything to work. I needed vision for a
+robotics project so I borrowed this camera from a friend and started hacking.
+Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into
+a working Linux driver.
 
-Ok, after a lot of work in softice, wdasm, reading pdf-files
-and trial-and-error work I've finally got everything to work.
-Since I needed some vision for a robotics project I borrowed
-this camera from a friend and started hacking. Anyway I've
-converted my original code from the AVR 8bit RISC C/asm
-into a working linux driver. I would really appreciate _any_
-kind of feedback regarding this driver.
-
-To get it working quickly configure your kernel
-to support parport, ieee1284, video4linux, experimental drivers
-and w9966
+To get it working simply configure your kernel to support
+parport, ieee1284, video4linux and w9966
 
-If w9966 is statically linked it will perform aggressive probing
-for the camera. If built as a module you'll have more configuration options.
+If w9966 is statically linked it will always perform aggressive probing for
+the camera. If built as a module you'll have more configuration options.
 
 Options:
-modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
- 
+ modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
 voila!
 
 you can also type 'modinfo -p w9966.o' for option usage
 (or checkout w9966.c)
 
-I've only tested it with custom built testprograms
-(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam.
-(you'll need to tweak the code to qcam a bit to make it work,
-dimensions and such)
+The only thing to keep in mind is that the image format is in Y-U-Y-V format
+where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format
+is called VIDEO_PALETTE_YUV422 (16 bpp).
+
+A minimal test application (with source) is available from:
+  http://hem.fyristorg.com/mogul/w9966.html
 
 The slow framerate is due to missing DMA ECP read support in the 
 parport drivers. I might add working EPP support later.
 
 Good luck!
-
-    /Jakob
+    /Jakob Kemi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.16/MAINTAINERS	Mon Nov 26 10:35:01 2001
+++ linux/MAINTAINERS	Mon Dec 10 18:50:48 2001
@@ -148,8 +148,8 @@
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
-L:	acpi@phobos.fs.tum.de
-W:	http://phobos.fs.tum.de/acpi/index.html
+L:	acpi-devel@lists.sourceforge.net
+W:	http://sf.net/projects/acpi/
 S:	Maintained
 
 AD1816 SOUND DRIVER
@@ -285,6 +285,14 @@
 M:	Nils Faerber <nils@kernelconcepts.de>
 S:	Maintained
 
+CODA FILE SYSTEM
+P:	Jan Harkes
+M:	jaharkes@cs.cmu.edu
+M:	coda@cs.cmu.edu
+L:	codalist@coda.cs.cmu.edu
+W:	http://www.coda.cs.cmu.edu/
+S:	Maintained
+
 COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
 P:      Amy Vanzant-Hodge 
 M:      Amy Vanzant-Hodge (fibrechannel@compaq.com)
@@ -404,6 +412,12 @@
 L:	linux-decnet-user@lists.sourceforge.net
 S:	Maintained
 
+DELL LAPTOP SMM DRIVER
+P:	Massimo Dal Zotto
+M:	dz@debian.org
+W:	http://www.debian.org/~dz/i8k/
+S:	Maintained
+
 DEVICE NUMBER REGISTRY
 P:	H. Peter Anvin
 M:	hpa@zytor.com
@@ -918,6 +932,12 @@
 W:     http://www.sistina.com/lvm
 S:     Maintained 
 
+LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers
+P:	Gerard Roudier
+M:	groudier@free.fr
+L:	linux-scsi@vger.kernel.org
+S:	Maintained
+
 M68K
 P:	Jes Sorensen
 M:	jes@trained-monkey.org
@@ -1660,8 +1680,8 @@
 W:	http://misc.nu/hugh/keyspan/
 
 USB SUBSYSTEM
-P:	Johannes Erdfelt
-M:	johannes@erdfelt.com
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.linux-usb.org
@@ -1684,10 +1704,8 @@
 
 VIA 82Cxxx AUDIO DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
 L:	linux-via@gtf.org
-W:	http://sourceforge.net/projects/gkernel/
-S:	Maintained
+S:	Odd fixes
 
 USB DIAMOND RIO500 DRIVER
 P:	Cesar Miquel
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/Makefile linux/Makefile
--- linux-2.4.16/Makefile	Mon Nov 26 10:35:11 2001
+++ linux/Makefile	Mon Dec 10 19:34:56 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 16
-EXTRAVERSION =
+SUBLEVEL = 17
+EXTRAVERSION = -pre8
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- linux-2.4.16/arch/alpha/kernel/smp.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/alpha/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/irq.h>
+#include <linux/cache.h>
 
 #include <asm/hwrpb.h>
 #include <asm/ptrace.h>
@@ -65,7 +66,7 @@
 	IPI_CPU_STOP,
 };
 
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* Set to a secondary's cpuid when it comes online.  */
 static unsigned long smp_secondary_alive;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.4.16/arch/i386/config.in	Mon Nov 26 10:35:03 2001
+++ linux/arch/i386/config.in	Tue Dec  4 19:28:47 2001
@@ -52,6 +52,7 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
    define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+   define_bool CONFIG_X86_PPRO_FENCE y
 else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
@@ -66,17 +67,20 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M586" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M586TSC" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M586MMX" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -84,6 +88,7 @@
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -91,6 +96,7 @@
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -149,7 +155,7 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
-tristate 'Dell Inspiron 8000 support' CONFIG_I8K
+tristate 'Dell laptop support' CONFIG_I8K
 
 tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE
 tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
--- linux-2.4.16/arch/i386/kernel/dmi_scan.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/i386/kernel/dmi_scan.c	Sun Dec  9 22:34:42 2001
@@ -523,6 +523,12 @@
 			MATCH(DMI_BIOS_DATE, "05/11/00"), NO_MATCH
 			} },
 
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600NE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "WME01Z1"),
+			MATCH(DMI_BIOS_DATE, "08/11/00"), NO_MATCH
+			} },
+
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0203D0"),
@@ -562,6 +568,11 @@
 	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
 			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
 			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
+			NO_MATCH, NO_MATCH
+                        } },
+	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
+			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"),
 			NO_MATCH, NO_MATCH
                         } },
 	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.4.16/arch/i386/kernel/setup.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/i386/kernel/setup.c	Mon Dec 10 19:01:14 2001
@@ -1280,9 +1280,27 @@
 			}
 			break;
 
-		case 6:	/* An Athlon/Duron. We can trust the BIOS probably */
-			mcheck_init(c);
-			break;		
+		case 6: /* An Athlon/Duron */
+ 
+			/* Bit 15 of Athlon specific MSR 15, needs to be 0
+ 			 * to enable SSE on Palomino/Morgan CPU's.
+			 * If the BIOS didn't enable it already, enable it
+			 * here.
+			 */
+			if (c->x86_model == 6 || c->x86_model == 7) {
+				if (!test_bit(X86_FEATURE_XMM,
+					      &c->x86_capability)) {
+					printk(KERN_INFO
+					       "Enabling Disabled K7/SSE Support...\n");
+					rdmsr(MSR_K7_HWCR, l, h);
+					l &= ~0x00008000;
+					wrmsr(MSR_K7_HWCR, l, h);
+					set_bit(X86_FEATURE_XMM,
+                                                &c->x86_capability);
+				}
+			}
+			break;
+
 	}
 
 	display_cacheinfo(c);
@@ -1909,7 +1927,6 @@
 				c->x86_cache_size = (cc>>24)+(dd>>24);
 			}
 			sprintf( c->x86_model_id, "WinChip %s", name );
-			mcheck_init(c);
 			break;
 
 		case 6:
@@ -2193,9 +2210,56 @@
 
 	if ( p )
 		strcpy(c->x86_model_id, p);
+	
+#ifdef CONFIG_SMP
+	if (test_bit(X86_FEATURE_HT, &c->x86_capability)) {
+		extern	int phys_proc_id[NR_CPUS];
+		
+		u32 	eax, ebx, ecx, edx;
+		int 	index_lsb, index_msb, tmp;
+		int	initial_apic_id;
+		int 	cpu = smp_processor_id();
+
+		cpuid(1, &eax, &ebx, &ecx, &edx);
+		smp_num_siblings = (ebx & 0xff0000) >> 16;
+
+		if (smp_num_siblings == 1) {
+			printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+		} else if (smp_num_siblings > 1 ) {
+			index_lsb = 0;
+			index_msb = 31;
+			/*
+			 * At this point we only support two siblings per
+			 * processor package.
+			 */
+#define NR_SIBLINGS	2
+			if (smp_num_siblings != NR_SIBLINGS) {
+				printk(KERN_WARNING "CPU: Unsuppored number of the siblings %d", smp_num_siblings);
+				smp_num_siblings = 1;
+				goto too_many_siblings;
+			}
+			tmp = smp_num_siblings;
+			while ((tmp & 1) == 0) {
+				tmp >>=1 ;
+				index_lsb++;
+			}
+			tmp = smp_num_siblings;
+			while ((tmp & 0x80000000 ) == 0) {
+				tmp <<=1 ;
+				index_msb--;
+			}
+			if (index_lsb != index_msb )
+				index_msb++;
+			initial_apic_id = ebx >> 24 & 0xff;
+			phys_proc_id[cpu] = initial_apic_id >> index_msb;
 
-	/* Enable MCA if available */
-	mcheck_init(c);
+			printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+                               phys_proc_id[cpu]);
+		}
+
+	}
+too_many_siblings:
+#endif
 }
 
 void __init get_cpu_vendor(struct cpuinfo_x86 *c)
@@ -2575,7 +2639,7 @@
 		init_rise(c);
 		break;
 	}
-	
+
 	printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
 	       c->x86_capability[0],
 	       c->x86_capability[1],
@@ -2602,6 +2666,9 @@
 	/* Disable the PN if appropriate */
 	squash_the_stupid_serial_number(c);
 
+	/* Init Machine Check Exception if available. */
+	mcheck_init(c);
+
 	/* If the model name is still unset, do table lookup. */
 	if ( !c->x86_model_id[0] ) {
 		char *p;
@@ -2699,7 +2766,7 @@
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
 	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
 	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-	        "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
+	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
 
 		/* AMD-defined */
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- linux-2.4.16/arch/i386/kernel/smp.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/i386/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -17,6 +17,7 @@
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
+#include <linux/cache.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
@@ -102,7 +103,7 @@
  */
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 struct tlb_state cpu_tlbstate[NR_CPUS] = {[0 ... NR_CPUS-1] = { &init_mm, 0 }};
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- linux-2.4.16/arch/i386/kernel/smpboot.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/i386/kernel/smpboot.c	Thu Dec  6 16:32:26 2001
@@ -56,6 +56,10 @@
 /* Total count of live CPUs */
 int smp_num_cpus = 1;
 
+/* Number of siblings per CPU package */
+int smp_num_siblings = 1;
+int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+
 /* Bitmask of currently online CPUs */
 unsigned long cpu_online_map;
 
@@ -971,6 +975,8 @@
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
 void *xquad_portio = NULL;
 
+int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+
 void __init smp_boot_cpus(void)
 {
 	int apicid, cpu, bit;
@@ -1162,6 +1168,34 @@
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	Dprintk("Boot done.\n");
 
+	/*
+	 * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so
+	 * that we can tell the sibling CPU efficiently.
+	 */
+	if (test_bit(X86_FEATURE_HT, boot_cpu_data.x86_capability)
+	    && smp_num_siblings > 1) {
+		for (cpu = 0; cpu < NR_CPUS; cpu++)
+			cpu_sibling_map[cpu] = NO_PROC_ID;
+		
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			int 	i;
+			
+			for (i = 0; i < smp_num_cpus; i++) {
+				if (i == cpu)
+					continue;
+				if (phys_proc_id[cpu] == phys_proc_id[i]) {
+					cpu_sibling_map[cpu] = i;
+					printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]);
+					break;
+				}
+			}
+			if (cpu_sibling_map[cpu] == NO_PROC_ID) {
+				smp_num_siblings = 1;
+				printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu);
+			}
+		}
+	}
+	     
 #ifndef CONFIG_VISWS
 	/*
 	 * Here we can be sure that there is an IO-APIC in the system. Let's
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- linux-2.4.16/arch/i386/mm/init.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/i386/mm/init.c	Tue Dec  4 19:25:30 2001
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
+#include <linux/slab.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -596,3 +597,17 @@
 	val->mem_unit = PAGE_SIZE;
 	return;
 }
+
+#if defined(CONFIG_X86_PAE)
+struct kmem_cache_s *pae_pgd_cachep;
+void __init pgtable_cache_init(void)
+{
+	/*
+	 * PAE pgds must be 16-byte aligned:
+	 */
+	pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0,
+		SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL);
+	if (!pae_pgd_cachep)
+		panic("init_pae(): Cannot alloc pae_pgd SLAB cache");
+}
+#endif /* CONFIG_X86_PAE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c
--- linux-2.4.16/arch/ia64/kernel/smp.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/ia64/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -30,6 +30,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -51,7 +52,7 @@
 #include <asm/mca.h>
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/mips/kernel/smp.c linux/arch/mips/kernel/smp.c
--- linux-2.4.16/arch/mips/kernel/smp.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/mips/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -31,6 +31,7 @@
 #include <linux/timex.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/processor.h>
@@ -52,7 +53,7 @@
 
 
 /* Ze Big Kernel Lock! */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;  /* Not used */
 int smp_num_cpus;    
 int global_irq_holder = NO_PROC_ID;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c
--- linux-2.4.16/arch/mips64/kernel/smp.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/mips64/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -5,6 +5,7 @@
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/processor.h>
@@ -52,7 +53,7 @@
 #endif /* CONFIG_SGI_IP27 */
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;	/* Not used */
 atomic_t smp_commenced = ATOMIC_INIT(0);
 struct cpuinfo_mips cpu_data[NR_CPUS];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- linux-2.4.16/arch/ppc/kernel/smp.c	Mon Nov 26 10:35:11 2001
+++ linux/arch/ppc/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -23,6 +23,7 @@
 #include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/cache.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -45,7 +46,7 @@
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
-spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 cycles_t cacheflush_time;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- linux-2.4.16/arch/s390/kernel/smp.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/s390/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -29,6 +29,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
@@ -55,7 +56,7 @@
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
-spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 unsigned long	 cpu_online_map;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c
--- linux-2.4.16/arch/s390x/kernel/smp.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/s390x/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -29,6 +29,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
@@ -55,7 +56,7 @@
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
-spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 unsigned long	 cpu_online_map;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc/defconfig linux/arch/sparc/defconfig
--- linux-2.4.16/arch/sparc/defconfig	Mon Nov 26 10:35:03 2001
+++ linux/arch/sparc/defconfig	Tue Dec  4 19:25:30 2001
@@ -138,7 +138,7 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -148,6 +148,7 @@
 # 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=m
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- linux-2.4.16/arch/sparc/kernel/process.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/sparc/kernel/process.c	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.157 2001/11/13 00:57:05 davem Exp $
+/*  $Id: process.c,v 1.158 2001/11/26 23:45:00 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -285,37 +285,29 @@
 	show_regwindow((struct reg_window *)regs->u_regs[14]);
 }
 
-#if NOTUSED
-void show_thread(struct thread_struct *thread)
+void show_trace_task(struct task_struct *tsk)
 {
-	int i;
-
-	printk("uwinmask:          0x%08lx  kregs:             0x%08lx\n", thread->uwinmask, (unsigned long)thread->kregs);
-	show_regs(thread->kregs);
-	printk("ksp:               0x%08lx  kpc:               0x%08lx\n", thread->ksp, thread->kpc);
-	printk("kpsr:              0x%08lx  kwim:              0x%08lx\n", thread->kpsr, thread->kwim);
-	printk("fork_kpsr:         0x%08lx  fork_kwim:         0x%08lx\n", thread->fork_kpsr, thread->fork_kwim);
-
-	for (i = 0; i < NSWINS; i++) {
-		if (!thread->rwbuf_stkptrs[i])
-			continue;
-		printk("reg_window[%d]:\n", i);
-		printk("stack ptr:         0x%08lx\n", thread->rwbuf_stkptrs[i]);
-		show_regwindow(&thread->reg_window[i]);
-	}
-	printk("w_saved:           0x%08lx\n", thread->w_saved);
-
-	/* XXX missing: float_regs */
-	printk("fsr:               0x%08lx  fpqdepth:          0x%08lx\n", thread->fsr, thread->fpqdepth);
-	/* XXX missing: fpqueue */
+	unsigned long pc, fp;
+	unsigned long task_base = (unsigned long) tsk;
+	struct reg_window *rw;
+	int count = 0;
 
-	printk("flags:             0x%08lx  current_ds:        0x%08lx\n", thread->flags, thread->current_ds.seg);
-	
-	show_regwindow((struct reg_window *)thread->ksp);
+	if (!tsk)
+		return;
 
-	/* XXX missing: core_exec */
+	fp = tsk->thread.ksp;
+	do {
+		/* Bogus frame pointer? */
+		if (fp < (task_base + sizeof(struct task_struct)) ||
+		    fp >= (task_base + (PAGE_SIZE << 1)))
+			break;
+		rw = (struct reg_window *) fp;
+		pc = rw->ins[7];
+		printk("[%08lx] ", pc);
+		fp = rw->ins[6];
+	} while (++count < 16);
+	printk("\n");
 }
-#endif
 
 /*
  * Free current thread data structures etc..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- linux-2.4.16/arch/sparc/kernel/smp.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/sparc/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/cache.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -66,7 +67,7 @@
  */
 
 /* Kernel spinlock */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* Used to make bitops atomic */
 unsigned char bitops_spinlock = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc/mm/extable.c linux/arch/sparc/mm/extable.c
--- linux-2.4.16/arch/sparc/mm/extable.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/sparc/mm/extable.c	Tue Dec  4 19:25:30 2001
@@ -11,35 +11,49 @@
 
 static unsigned long
 search_one_table(const struct exception_table_entry *start,
-		 const struct exception_table_entry *last,
+		 const struct exception_table_entry *end,
 		 unsigned long value, unsigned long *g2)
 {
-	const struct exception_table_entry *first = start;
-	const struct exception_table_entry *mid;
-	long diff = 0;
-        while (first <= last) {
-		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0) {
-                	if (!mid->fixup) {
-                		*g2 = 0;
-                		return (mid + 1)->fixup;
-                	} else
-	                        return mid->fixup;
-                } else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        if (last->insn < value && !last->fixup && last[1].insn > value) {
-        	*g2 = (value - last->insn)/4;
-        	return last[1].fixup;
-        }
-        if (first > start && first[-1].insn < value
-	    && !first[-1].fixup && first->insn < value) {
-        	*g2 = (value - first[-1].insn)/4;
-        	return first->fixup;
-        }
+	const struct exception_table_entry *walk;
+
+	/* Single insn entries are encoded as:
+	 *	word 1:	insn address
+	 *	word 2:	fixup code address
+	 *
+	 * Range entries are encoded as:
+	 *	word 1: first insn address
+	 *	word 2: 0
+	 *	word 3: last insn address + 4 bytes
+	 *	word 4: fixup code address
+	 *
+	 * See asm/uaccess.h for more details.
+	 */
+
+	/* 1. Try to find an exact match. */
+	for (walk = start; walk <= end; walk++) {
+		if (walk->fixup == 0) {
+			/* A range entry, skip both parts. */
+			walk++;
+			continue;
+		}
+
+		if (walk->insn == value)
+			return walk->fixup;
+	}
+
+	/* 2. Try to find a range match. */
+	for (walk = start; walk <= (end - 1); walk++) {
+		if (walk->fixup)
+			continue;
+
+		if (walk[0].insn <= value &&
+		    walk[1].insn > value) {
+			*g2 = (value - walk[0].insn) / 4;
+			return walk[1].fixup;
+		}
+		walk++;
+	}
+
         return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- linux-2.4.16/arch/sparc/mm/fault.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/sparc/mm/fault.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.121 2001/10/30 04:54:22 davem Exp $
+/* $Id: fault.c,v 1.122 2001/11/17 07:19:26 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -155,34 +155,47 @@
 asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
 			    unsigned long address)
 {
+	struct pt_regs regs;
 	unsigned long g2;
+	unsigned int insn;
 	int i;
-	unsigned insn;
-	struct pt_regs regs;
 	
-	i = search_exception_table (ret_pc, &g2);
+	i = search_exception_table(ret_pc, &g2);
 	switch (i) {
-	/* load & store will be handled by fixup */
-	case 3: return 3;
-	/* store will be handled by fixup, load will bump out */
-	/* for _to_ macros */
-	case 1: insn = (unsigned)pc; if ((insn >> 21) & 1) return 1; break;
-	/* load will be handled by fixup, store will bump out */
-	/* for _from_ macros */
-	case 2: insn = (unsigned)pc; 
-		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; 
+	case 3:
+		/* load & store will be handled by fixup */
+		return 3;
+
+	case 1:
+		/* store will be handled by fixup, load will bump out */
+		/* for _to_ macros */
+		insn = *((unsigned int *) pc);
+		if ((insn >> 21) & 1)
+			return 1;
+		break;
+
+	case 2:
+		/* load will be handled by fixup, store will bump out */
+		/* for _from_ macros */
+		insn = *((unsigned int *) pc);
+		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
+			return 2; 
 		break; 
-	default: break;
-	}
-	memset (&regs, 0, sizeof (regs));
+
+	default:
+		break;
+	};
+
+	memset(&regs, 0, sizeof (regs));
 	regs.pc = pc;
 	regs.npc = pc + 4;
-	__asm__ __volatile__ (
+	__asm__ __volatile__(
 		"rd %%psr, %0\n\t"
 		"nop\n\t"
 		"nop\n\t"
 		"nop\n" : "=r" (regs.psr));
-	unhandled_fault (address, current, &regs);
+	unhandled_fault(address, current, &regs);
+
 	/* Not reached */
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- linux-2.4.16/arch/sparc/mm/init.c	Mon Nov 26 10:35:03 2001
+++ linux/arch/sparc/mm/init.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.100 2001/09/21 22:51:47 davem Exp $
+/*  $Id: init.c,v 1.103 2001/11/19 19:03:08 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -410,9 +410,6 @@
 	int datapages = 0;
 	int initpages = 0; 
 	int i;
-#ifdef CONFIG_BLK_DEV_INITRD
-	unsigned long addr, last;
-#endif
 
 	highmem_start_page = mem_map + highstart_pfn;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- linux-2.4.16/arch/sparc64/Makefile	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/Makefile	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.49 2001/10/17 18:26:58 davem Exp $
+# $Id: Makefile,v 1.51 2001/11/17 00:15:27 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -38,11 +38,6 @@
 AS		:= $(AS) --undeclared-regs
 endif
 
-#
-# Uncomment the first CFLAGS if you are doing kgdb source level
-# debugging of the kernel to get the proper debugging information.
-
-#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 
 ifneq ($(NEW_GCC),y)
   CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
@@ -51,25 +46,6 @@
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \
 	    $(CC_UNDECL)
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
-endif
-
-# Uncomment this to get spinlock/rwlock debugging on SMP.
-# DEBUG_SPINLOCK = 1
-
-ifdef CONFIG_SMP
-  ifdef DEBUG_SPINLOCK
-    CFLAGS += -DSPIN_LOCK_DEBUG
-    AFLAGS += -DSPIN_LOCK_DEBUG
-  endif
-endif
-
-# Uncomment this to keep track of how often flush_dcache_page
-# actually flushes the caches, output via /proc/cpuinfo
-#
-# DEBUG_DCACHE_FLUSH = 1
-ifdef DEBUG_DCACHE_FLUSH
-  CFLAGS += -DDCFLUSH_DEBUG
-  AFLAGS += -DDCFLUSH_DEBUG
 endif
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.4.16/arch/sparc64/config.in	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/config.in	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.152 2001/11/12 10:20:47 davem Exp $
+# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -31,6 +31,8 @@
 # Identify this as a Sparc64 build
 define_bool CONFIG_SPARC64 y
 
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
 # Global things across all Sun machines.
 define_bool CONFIG_HAVE_DEC_LOCK y
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
@@ -89,7 +91,6 @@
 mainmenu_option next_comment
 comment 'Console drivers'
 bool 'PROM console' CONFIG_PROM_CONSOLE
-bool 'Support Frame buffer devices' CONFIG_FB
 source drivers/video/Config.in
 endmenu
 
@@ -191,21 +192,21 @@
       if [ "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then
          dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
          dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-      fi
-      if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-	 int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
-	 int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
-	 int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
-	 bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
-         if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-	    bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+         if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+            int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+            int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
+            int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
+            bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
+            if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+	       bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+            fi
+            if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
+               bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+            fi
+            if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+               bool '  assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+            fi
          fi
-	 if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
-	    bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
-	 fi
-	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '  assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
-	 fi
       fi
       dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
       dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
@@ -295,6 +296,13 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+   bool '  D-cache flush debugging' CONFIG_DEBUG_DCFLUSH
+fi
+
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.4.16/arch/sparc64/defconfig	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/defconfig	Thu Dec  6 15:33:53 2001
@@ -22,6 +22,7 @@
 CONFIG_VT_CONSOLE=y
 CONFIG_SMP=y
 CONFIG_SPARC64=y
+CONFIG_HOTPLUG=y
 CONFIG_HAVE_DEC_LOCK=y
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -84,7 +85,6 @@
 # Console drivers
 #
 CONFIG_PROM_CONSOLE=y
-CONFIG_FB=y
 
 #
 # Frame-buffer support
@@ -158,15 +158,16 @@
 #
 # 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
-# CONFIG_BLK_DEV_RAM is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
@@ -174,8 +175,6 @@
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -354,15 +353,11 @@
 CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_OLD_PROC_STATS=y
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=m
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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_QLOGIC_ISP=m
 CONFIG_SCSI_QLOGIC_FC=y
 CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
@@ -493,6 +488,7 @@
 CONFIG_SUNDANCE=m
 # CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
 CONFIG_WINBOND_840=m
 # CONFIG_NET_POCKET is not set
 
@@ -539,7 +535,7 @@
 CONFIG_NET_FC=y
 # CONFIG_IPHASE5526 is not set
 # CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+CONFIG_SHAPER=m
 
 #
 # Wan interfaces
@@ -861,4 +857,9 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_DCFLUSH is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- linux-2.4.16/arch/sparc64/kernel/Makefile	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/Makefile	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.67 2001/05/11 04:31:55 davem Exp $
+# $Id: Makefile,v 1.69 2001/11/19 04:09:53 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -68,7 +68,7 @@
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -95,12 +95,12 @@
 	./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 SPIN_LOCK_DEBUG\n" >>asm_offsets.h
+	@echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -127,9 +127,9 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
-	$(CPP) $(CPPFLAGS) -DSPIN_LOCK_DEBUG tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -140,7 +140,7 @@
 	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
 	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
 	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
+	$(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
 	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
@@ -156,7 +156,7 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
 	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- linux-2.4.16/arch/sparc64/kernel/entry.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/entry.S	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.137 2001/10/18 09:06:36 davem Exp $
+/* $Id: entry.S,v 1.141 2001/12/05 23:56:32 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -483,7 +483,11 @@
 	ldxa		[%g7 + %g0] ASI_INTR_R, %g7
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
-	jmpl		%g3, %g0
+	ba,pt		%xcc, 1f
+	 nop
+
+	.align		32
+1:	jmpl		%g3, %g0
 	 nop
 
 do_ivec_spurious:
@@ -657,15 +661,15 @@
 	stx		%g5, [%g1 + %lo(pdma_size)]
 	sethi		%hi(auxio_register), %g1
 	ldx		[%g1 + %lo(auxio_register)], %g7
-	ldub		[%g7], %g5
+	lduba		[%g7] ASI_PHYS_BYPASS_EC_E, %g5
 	or		%g5, 0xc2, %g5
-	stb		%g5, [%g7]
+	stba		%g5, [%g7] ASI_PHYS_BYPASS_EC_E
 	andn		%g5, 0x02, %g5
 
 	nop; nop;  nop; nop;  nop; nop;
 	nop; nop;  nop; nop;  nop; nop;
 
-	stb		%g5, [%g7]
+	stba		%g5, [%g7] ASI_PHYS_BYPASS_EC_E
 	sethi		%hi(doing_pdma), %g1
 	b,pt		%xcc, floppy_dosoftint
 	 st		%g0, [%g1 + %lo(doing_pdma)]
@@ -678,7 +682,12 @@
 	sethi		%hi(irq_action), %g1
 	or		%g1, %lo(irq_action), %g1
 	ldx		[%g1 + (11 << 3)], %g3		! irqaction[floppy_irq]
-	ldx		[%g3 + 0x10], %g4		! action->mask == ino_bucket ptr
+	ldx		[%g3 + 0x08], %g4		! action->flags>>48==ino
+	sethi		%hi(ivector_table), %g3
+	srlx		%g4, 48, %g4
+	or		%g3, %lo(ivector_table), %g3
+	sllx		%g4, 5, %g4
+	ldx		[%g3 + %g4], %g4		! &ivector_table[ino]
 	ldx		[%g4 + 0x10], %g4		! bucket->iclr
 	stwa		%g0, [%g4] ASI_PHYS_BYPASS_EC_E	! ICLR_IDLE
 	membar		#Sync				! probably not needed...
@@ -1615,6 +1624,11 @@
 	 *
 	 * Note with time_t changes to the timeval type, I must now use
 	 * nucleus atomic quad 128-bit loads.
+	 *
+	 * If xtime was stored recently, I've seen crap from the
+	 * quad load on Cheetah.  Putting a membar SYNC before
+	 * the quad load seems to make the problem go away. -DaveM
+	 * (we should nop out workarounds like this on spitfire)
 	 */
 	sethi	%hi(timer_tick_offset), %g3
 	sethi	%hi(xtime), %g2
@@ -1626,6 +1640,7 @@
 	sethi	%hi(0x003e0014), %o1
 	srlx	%o2, 32, %o2
 	or	%o1, %lo(0x003e0014), %o1
+	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
 	cmp	%o2, %o1
 	bne,pt	%xcc, 2f
@@ -1634,6 +1649,7 @@
 	 rd	%asr24, %o1
 2:	rd	%tick, %o1
 3:	ldx	[%g1], %g7
+	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o2
 	xor	%o4, %o2, %o2
 	xor	%o5, %o3, %o3
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- linux-2.4.16/arch/sparc64/kernel/head.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/head.S	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.82 2001/10/04 23:37:04 davem Exp $
+/* $Id: head.S,v 1.86 2001/12/05 01:02:16 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -201,7 +201,7 @@
 	 add	%l0, (1 << 3), %l0
 
 	/* Now lock the TTE we created into ITLB-0 and DTLB-0,
-	 * entry 15.
+	 * entry 15 (and maybe 14 too).
 	 */
 	sethi	%hi(KERNBASE), %g3
 	set	(0 << 16) | (15 << 3), %g7
@@ -215,6 +215,29 @@
 	membar	#Sync
 	flush	%g3
 	membar	#Sync
+	sethi	%hi(_end), %g3			/* Check for bigkernel case */
+	or	%g3, %lo(_end), %g3
+	srl	%g3, 23, %g3			/* Check if _end > 8M */
+	brz,pt	%g3, 1f
+	 sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
+	sethi	%hi(0x400000), %g3
+	or	%g3, %lo(0x400000), %g3
+	add	%g5, %g3, %g5			/* New tte data */
+	andn	%g5, (_PAGE_G), %g5
+	sethi	%hi(KERNBASE+0x400000), %g3
+	or	%g3, %lo(KERNBASE+0x400000), %g3
+	set	(0 << 16) | (14 << 3), %g7
+	stxa	%g3, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	stxa	%g3, [%l7] ASI_IMMU
+	membar	#Sync
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+	flush	%g3
+	membar	#Sync
+	sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
 	ba,pt	%xcc, 1f
 	 nop
 
@@ -345,7 +368,7 @@
 
 
 	/* PROM never puts any TLB entries into the MMU with the lock bit
-	 * set.  So we gladly use tlb entry 63 for KERNBASE.
+	 * set.  So we gladly use tlb entry 63 for KERNBASE. And maybe 62 too.
 	 */
 
 	sethi	%hi(KERNBASE), %g3
@@ -358,7 +381,28 @@
 	membar	#Sync
 	flush	%g3
 	membar	#Sync
-	ba,pt	%xcc, 1f
+	sethi	%hi(_end), %g3			/* Check for bigkernel case */
+	or	%g3, %lo(_end), %g3
+	srl	%g3, 23, %g3			/* Check if _end > 8M */
+	brz,pt	%g3, 2f
+	 sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
+	sethi	%hi(0x400000), %g3
+	or	%g3, %lo(0x400000), %g3
+	add	%g5, %g3, %g5			/* New tte data */
+	andn	%g5, (_PAGE_G), %g5
+	sethi	%hi(KERNBASE+0x400000), %g3
+	or	%g3, %lo(KERNBASE+0x400000), %g3
+	mov	(62 << 3), %g7
+	stxa	%g3, [%l7] ASI_DMMU
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	stxa	%g3, [%l7] ASI_IMMU
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+	flush	%g3
+	membar	#Sync
+	sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
+2:	ba,pt	%xcc, 1f
 	 nop
 1:
 	set	sun4u_init, %g2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.16/arch/sparc64/kernel/ioctl32.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.132 2001/11/07 05:56:19 davem Exp $
+/* $Id: ioctl32.c,v 1.133 2001/11/14 06:14:29 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -2421,6 +2421,7 @@
 	u32 pv[ABS_MAX_PV + 1];
 	u32 lv[ABS_MAX_LV + 1];
     	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	uint8_t dummy1[200];
 } vg32_t;
 
 typedef struct {
@@ -2462,7 +2463,7 @@
 } lv_status_byindex_req32_t;
 
 typedef struct {
-	dev_t dev;
+	__kernel_dev_t32 dev;
 	u32   lv;
 } lv_status_bydev_req32_t;
 
@@ -2535,7 +2536,8 @@
 	lv_block_exception32_t *lbe32;
 	lv_block_exception_t *lbe;
 	lv32_t *ul = (lv32_t *)A(p);
-	lv_t *l = (lv_t *)kmalloc(sizeof(lv_t), GFP_KERNEL);
+	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
 	if (!l) {
 		*errp = -ENOMEM;
 		return NULL;
@@ -2565,12 +2567,11 @@
 		if (l->lv_block_exception) {
 			lbe32 = (lv_block_exception32_t *)A(ptr2);
 			memset(lbe, 0, size);
-                       for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
-                               err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
-                               err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
-                               err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
-                               err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
 			}
 		}
 	}
@@ -2608,7 +2609,7 @@
 
 static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	vg_t *v;
+	vg_t *v = NULL;
 	union {
 		lv_req_t lv_req;
 		le_remap_req_t le_remap;
@@ -2626,17 +2627,22 @@
 	switch (cmd) {
 	case VG_STATUS:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
+		if (!v)
+			return -ENOMEM;
 		karg = v;
 		break;
+
+	case VG_CREATE_OLD:
 	case VG_CREATE:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
-		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
-		    __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
 			kfree(v);
 			return -EFAULT;
 		}
+		/* 'proc' field is unused, just NULL it out. */
+		v->proc = NULL;
 		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
 			kfree(v);
 			return -EFAULT;
@@ -2648,39 +2654,46 @@
 			return -EPERM;
 		for (i = 0; i < v->pv_max; i++) {
 			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
-			if (err) break;
+			if (err)
+				break;
 			if (ptr) {
 				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
 				if (!v->pv[i]) {
 					err = -ENOMEM;
 					break;
 				}
-				err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
 				if (err) {
 					err = -EFAULT;
 					break;
 				}
-				err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
 				if (err) {
 				        err = -EFAULT;
 					break;
 				}
 
-				
-				v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
 			}
 		}
 		if (!err) {
 			for (i = 0; i < v->lv_max; i++) {
 				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
-				if (err) break;
+				if (err)
+					break;
 				if (ptr) {
 					v->lv[i] = get_lv_t(ptr, &err);
-					if (err) break;
+					if (err)
+						break;
 				}
 			}
 		}
 		break;
+
 	case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
@@ -2688,54 +2701,70 @@
 	case LV_RENAME:
 	case LV_STATUS_BYNAME:
 	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		if (cmd != LV_REMOVE) {
 			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
-			if (err) return err;
+			if (err)
+				return err;
 			u.lv_req.lv = get_lv_t(ptr, &err);
 		} else
 			u.lv_req.lv = NULL;
 		break;
 
-
 	case LV_STATUS_BYINDEX:
-		err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
 		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.lv_byindex.lv = get_lv_t(ptr, &err);
 		break;
+
 	case LV_STATUS_BYDEV:
 	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
 		u.lv_bydev.lv = get_lv_t(ptr, &err);
-		if (err) return err;
-		u.lv_bydev.lv = &p;
-		p.pe = NULL; p.inode = NULL;		
-		break;		
+		break;
+
 	case VG_EXTEND:
 		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
-		if (err) return -EFAULT;
-		p.pe = NULL; p.inode = NULL;
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
 		karg = &p;
 		break;
+
 	case PV_CHANGE:
 	case PV_STATUS:
 		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.pv_status.pv = &p;
 		if (cmd == PV_CHANGE) {
-			err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
-			p.pe = NULL; p.inode = NULL;
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
 		}
 		break;
-	}
+	};
+
         old_fs = get_fs(); set_fs (KERNEL_DS);
         err = sys_ioctl (fd, cmd, (unsigned long)karg);
         set_fs (old_fs);
+
 	switch (cmd) {
 	case VG_STATUS:
 		if (!err) {
@@ -2748,42 +2777,60 @@
 		}
 		kfree(v);
 		break;
+
+	case VG_CREATE_OLD:
 	case VG_CREATE:
-		for (i = 0; i < v->pv_max; i++)
-			if (v->pv[i]) kfree(v->pv[i]);
-		for (i = 0; i < v->lv_max; i++)
-			if (v->lv[i]) put_lv_t(v->lv[i]);
+		for (i = 0; i < v->pv_max; i++) {
+			if (v->pv[i])
+				kfree(v->pv[i]);
+		}
+		for (i = 0; i < v->lv_max; i++) {
+			if (v->lv[i])
+				put_lv_t(v->lv[i]);
+		}
 		kfree(v);
 		break;
+
 	case LV_STATUS_BYNAME:
-		if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
 		/* Fall through */
+
         case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
-		if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
 		break;
+
 	case LV_STATUS_BYINDEX:
 		if (u.lv_byindex.lv) {
-			if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
 			put_lv_t(u.lv_byindex.lv);
 		}
 		break;
+
+	case LV_STATUS_BYDEV:
+	        if (u.lv_bydev.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_bydev.lv);
+			put_lv_t(u.lv_byindex.lv);
+	        }
+	        break;
+
 	case PV_STATUS:
 		if (!err) {
 			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 		}
 		break;
-	case LV_STATUS_BYDEV:
-	        if (!err) {
-			if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv);
-			put_lv_t(u.lv_byindex.lv);
-	        }
-	        break;
-	}
+	};
+
 	return err;
 }
 #endif
@@ -4666,6 +4713,7 @@
 HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
 HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
 HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
 HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
@@ -4675,6 +4723,7 @@
 HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
 HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
 HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
 #endif /* LVM */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- linux-2.4.16/arch/sparc64/kernel/irq.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/irq.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.109 2001/11/12 22:22:37 davem Exp $
+/* $Id: irq.c,v 1.112 2001/11/16 00:04:54 kanoj Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
+#include <linux/kbd_ll.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -34,6 +35,7 @@
 #include <asm/softirq.h>
 #include <asm/starfire.h>
 #include <asm/uaccess.h>
+#include <asm/cache.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -52,10 +54,10 @@
  * at the same time.
  */
 
-struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64)));
+struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 #ifndef CONFIG_SMP
-unsigned int __up_workvec[16] __attribute__ ((aligned (64)));
+unsigned int __up_workvec[16] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 #define irq_work(__cpu, __pil)	&(__up_workvec[(void)(__cpu), (__pil)])
 #else
 #define irq_work(__cpu, __pil)	&(cpu_data[(__cpu)].irq_worklists[(__pil)])
@@ -821,6 +823,11 @@
 
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq]++;
+
+#ifdef CONFIG_PCI
+	if (irq == 9)
+		kbd_pt_regs = regs;
+#endif
 
 	/* Sliiiick... */
 #ifndef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- linux-2.4.16/arch/sparc64/kernel/pci_psycho.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.29 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_psycho.c,v 1.30 2001/11/14 13:17:56 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -371,6 +371,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- linux-2.4.16/arch/sparc64/kernel/pci_sabre.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.40 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -589,6 +589,11 @@
 {
 	int ret;
 
+	if (pdev &&
+	    pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 9;
+
 	ret = sabre_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
@@ -609,6 +614,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.16/arch/sparc64/kernel/pci_schizo.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.22 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -337,6 +337,11 @@
 {
 	int ret;
 
+	if (pdev &&
+	    pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 9;
+
 	ret = schizo_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
@@ -357,6 +362,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- linux-2.4.16/arch/sparc64/kernel/process.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/process.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.122 2001/10/18 09:06:36 davem Exp $
+/*  $Id: process.c,v 1.125 2001/11/17 00:10:48 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -276,7 +276,12 @@
 #ifdef CONFIG_SMP
 	unsigned long flags;
 
-	spin_lock_irqsave(&regdump_lock, flags);
+	/* Protect against xcall ipis which might lead to livelock on the lock */
+	__asm__ __volatile__("rdpr      %%pstate, %0\n\t"
+			     "wrpr      %0, %1, %%pstate"
+			     : "=r" (flags)
+			     : "i" (PSTATE_IE));
+	spin_lock(&regdump_lock);
 	printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n",
 	       smp_processor_id(),
 	       local_irq_count(smp_processor_id()),
@@ -298,7 +303,9 @@
 	       regs->u_regs[15]);
 	show_regwindow(regs);
 #ifdef CONFIG_SMP
-	spin_unlock_irqrestore(&regdump_lock, flags);
+	spin_unlock(&regdump_lock);
+	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
+			     : : "r" (flags));
 #endif
 }
 
@@ -583,6 +590,11 @@
 {
 	struct thread_struct *t = &p->thread;
 	char *child_trap_frame;
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+	t->smp_lock_count = 0;
+	t->smp_lock_pc = 0;
+#endif
 
 	/* Calculate offset to stack_frame & pt_regs */
 	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- linux-2.4.16/arch/sparc64/kernel/rtrap.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/rtrap.S	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.56 2001/10/13 00:14:34 kanoj Exp $
+/* $Id: rtrap.S,v 1.57 2001/12/06 00:16:11 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -18,14 +18,13 @@
 #define		RTRAP_PSTATE_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
 #define		RTRAP_PSTATE_AG_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
 
-#if 0
-#define		RTRAP_CHECK		call rtrap_check;  add %sp, (STACK_BIAS+REGWIN_SZ), %o0;
-#else
-#define		RTRAP_CHECK
-#endif
+		/* Register %l6 keeps track of whether we are returning
+		 * from a system call or not.  It is cleared if we call
+		 * do_signal, and it must not be otherwise modified until
+		 * we fully commit to returning to userspace.
+		 */
 
 		.text
-
 		.align			32
 __handle_softirq:
 		call			do_softirq
@@ -34,42 +33,101 @@
 		 nop
 __handle_preemption:
 		call			schedule
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		ba,pt			%xcc, __handle_preemption_continue
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+
 __handle_user_windows:
-		wrpr			%g0, RTRAP_PSTATE, %pstate
 		call			fault_in_user_windows
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		ba,pt			%xcc, __handle_user_windows_continue
+		 wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		/* Redo sched+sig checks */
+		ldx			[%g6 + AOFF_task_need_resched], %l0
+		brz,pt			%l0, 1f
+		 nop
+		call			schedule
+
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+1:		lduw			[%g6 + AOFF_task_sigpending], %l0
+		brz,pt			%l0, __handle_user_windows_continue
 		 nop
+		clr			%o0
+		mov			%l5, %o2
+		mov			%l6, %o3
+
+		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		call			do_signal
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		clr			%l6
+		/* Signal delivery can modify pt_regs tstate, so we must
+		 * reload it.
+		 */
+		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+		sethi			%hi(0xf << 20), %l4
+		and			%l1, %l4, %l4
+
+		ba,pt			%xcc, __handle_user_windows_continue
+		 andn			%l1, %l4, %l1
 __handle_perfctrs:
-		/* Don't forget to preserve user window invariants. */
-		wrpr			%g0, RTRAP_PSTATE, %pstate
 		call			update_perfctrs
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
-		brz,pt			%o2, __handle_perfctrs_continue
-		 sethi			%hi(TSTATE_PEF), %l6
-		wrpr			%g0, RTRAP_PSTATE, %pstate
+		brz,pt			%o2, 1f
+		 nop
 
+		/* Redo userwin+sched+sig checks */
 		call			fault_in_user_windows
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+1:		ldx			[%g6 + AOFF_task_need_resched], %l0
+		brz,pt			%l0, 1f
 		 nop
+		call			schedule
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+1:		lduw			[%g6 + AOFF_task_sigpending], %l0
+		brz,pt			%l0, __handle_perfctrs_continue
+		 sethi			%hi(TSTATE_PEF), %o0
+		clr			%o0
+		mov			%l5, %o2
+		mov			%l6, %o3
+		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+
+		call			do_signal
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		clr			%l6
+		/* Signal delivery can modify pt_regs tstate, so we must
+		 * reload it.
+		 */
+		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+		sethi			%hi(0xf << 20), %l4
+		and			%l1, %l4, %l4
+		andn			%l1, %l4, %l1
+
 		ba,pt			%xcc, __handle_perfctrs_continue
-		 nop
+		 sethi			%hi(TSTATE_PEF), %o0
 __handle_userfpu:
 		rd			%fprs, %l5
 		andcc			%l5, FPRS_FEF, %g0
+		sethi			%hi(TSTATE_PEF), %o0
 		be,a,pn			%icc, __handle_userfpu_continue
-		 andn			%l1, %l6, %l1
+		 andn			%l1, %o0, %l1
 		ba,a,pt			%xcc, __handle_userfpu_continue
+
 __handle_signal:
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
+		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
 		call			do_signal
-		 add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		clr			%l6
 
 		/* Signal delivery can modify pt_regs tstate, so we must
@@ -99,29 +157,43 @@
 		and			%l1, %l4, %l4
 		bne,pn			%icc, to_kernel
 		 andn			%l1, %l4, %l1
-to_user:	ldx			[%g6 + AOFF_task_need_resched], %l0
 
-		brnz,pn			%l0, __handle_preemption
+		/* We must hold IRQs off and atomically test schedule+signal
+		 * state, then hold them off all the way back to userspace.
+		 * If we are returning to kernel, none of this matters.
+		 *
+		 * If we do not do this, there is a window where we would do
+		 * the tests, later the signal/resched event arrives but we do
+		 * not process it since we are still in kernel mode.  It would
+		 * take until the next local IRQ before the signal/resched
+		 * event would be handled.
+		 *
+		 * This also means that if we have to deal with performance
+		 * counters or user windows, we have to redo all of these
+		 * sched+signal checks with IRQs disabled.
+		 */
+to_user:	wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 __handle_preemption_continue:
+		ldx			[%g6 + AOFF_task_need_resched], %l0
+		brnz,pn			%l0, __handle_preemption
 		 lduw			[%g6 + AOFF_task_sigpending], %l0
 		brnz,pn			%l0, __handle_signal
 		 nop
 __handle_signal_continue:
-check_user_wins:
-		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
 		brnz,pn			%o2, __handle_user_windows
-		 sethi			%hi(TSTATE_PEF), %l6
-
+		 nop
 __handle_user_windows_continue:
-		RTRAP_CHECK
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
 		andcc			%l5, SPARC_FLAG_PERFCTR, %g0
+		sethi			%hi(TSTATE_PEF), %o0
 		bne,pn			%xcc, __handle_perfctrs
 __handle_perfctrs_continue:
-		 andcc			%l1, %l6, %g0
+		 andcc			%l1, %o0, %g0
+
+		/* This fpdepth clear is neccessary for non-syscall rtraps only */
 		bne,pn			%xcc, __handle_userfpu
-		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
 __handle_userfpu_continue:
 
 rt_continue:	ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c
--- linux-2.4.16/arch/sparc64/kernel/semaphore.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/semaphore.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.8 2001/05/18 08:01:35 davem Exp $
+/* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
  * semaphore.c: Sparc64 semaphore implementation.
  *
  * This is basically the PPC semaphore scheme ported to use
@@ -31,7 +31,7 @@
 "	cas	[%3], %0, %1\n"
 "	cmp	%0, %1\n"
 "	bne,pn	%%icc, 1b\n"
-"	 nop\n"
+"	 membar #StoreLoad | #StoreStore\n"
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
 	: "r" (&sem->count), "r" (incr), "m" (sem->count)
 	: "cc");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- linux-2.4.16/arch/sparc64/kernel/smp.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/smp.c	Fri Dec  7 18:58:23 2001
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/cache.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -39,17 +40,17 @@
 extern void calibrate_delay(void);
 extern unsigned prom_cpu_nodes[];
 
-struct cpuinfo_sparc cpu_data[NR_CPUS]  __attribute__ ((aligned (64)));
+cpuinfo_sparc cpu_data[NR_CPUS];
 
-volatile int __cpu_number_map[NR_CPUS]  __attribute__ ((aligned (64)));
-volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (64)));
+volatile int __cpu_number_map[NR_CPUS]  __attribute__ ((aligned (SMP_CACHE_BYTES)));
+volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 /* Please don't make this stuff initdata!!!  --DaveM */
 static unsigned char boot_cpu_id = 0;
 static int smp_activated = 0;
 
 /* Kernel spinlock */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 volatile int smp_processors_ready = 0;
 unsigned long cpu_present_map = 0;
@@ -137,6 +138,15 @@
 {
 	int cpuid = hard_smp_processor_id();
 	unsigned long pstate;
+	extern int bigkernel;
+	extern unsigned long kern_locked_tte_data;
+
+	if (bigkernel) {
+		prom_dtlb_load(sparc64_highest_locked_tlbent()-1, 
+			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
+		prom_itlb_load(sparc64_highest_locked_tlbent()-1, 
+			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
+	}
 
 	inherit_locked_prom_mappings(0);
 
@@ -223,7 +233,6 @@
 {
 	trap_init();
 	init_IRQ();
-	smp_callin();
 	return cpu_idle();
 }
 
@@ -276,7 +285,7 @@
 			init_tasks[cpucount] = p;
 
 			p->processor = i;
-			p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+			p->cpus_runnable = 1UL << i; /* we schedule the first task manually */
 
 			del_from_runqueue(p);
 			unhash_process(p);
@@ -482,7 +491,7 @@
 		__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
 				     : : "r" (pstate));
 
-		if ((stuck & ~(0x5555555555555555UL)) == 0) {
+		if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) {
 			/* Busy bits will not clear, continue instead
 			 * of freezing up on this cpu.
 			 */
@@ -542,6 +551,9 @@
 	int wait;
 };
 
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static struct call_data_struct *call_data;
+
 extern unsigned long xcall_call_function;
 
 int smp_call_function(void (*func)(void *info), void *info,
@@ -549,6 +561,7 @@
 {
 	struct call_data_struct data;
 	int cpus = smp_num_cpus - 1;
+	long timeout;
 
 	if (!cpus)
 		return 0;
@@ -558,19 +571,36 @@
 	atomic_set(&data.finished, 0);
 	data.wait = wait;
 
-	smp_cross_call(&xcall_call_function,
-		       0, (u64) &data, 0);
+	spin_lock_bh(&call_lock);
+
+	call_data = &data;
+
+	smp_cross_call(&xcall_call_function, 0, 0, 0);
+
 	/* 
 	 * Wait for other cpus to complete function or at
 	 * least snap the call data.
 	 */
-	while (atomic_read(&data.finished) != cpus)
+	timeout = 1000000;
+	while (atomic_read(&data.finished) != cpus) {
+		if (--timeout <= 0)
+			goto out_timeout;
 		barrier();
+		udelay(1);
+	}
+
+	spin_unlock_bh(&call_lock);
+
+	return 0;
 
+out_timeout:
+	spin_unlock_bh(&call_lock);
+	printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n",
+	       smp_num_cpus - 1, atomic_read(&data.finished));
 	return 0;
 }
 
-void smp_call_function_client(struct call_data_struct *call_data)
+void smp_call_function_client(void)
 {
 	void (*func) (void *info) = call_data->func;
 	void *info = call_data->info;
@@ -597,7 +627,7 @@
 extern unsigned long xcall_flush_dcache_page_cheetah;
 extern unsigned long xcall_flush_dcache_page_spitfire;
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 extern atomic_t dcpage_flushes;
 extern atomic_t dcpage_flushes_xcall;
 #endif
@@ -620,7 +650,7 @@
 	if (smp_processors_ready) {
 		unsigned long mask = 1UL << cpu;
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 		atomic_inc(&dcpage_flushes);
 #endif
 		if (cpu == smp_processor_id()) {
@@ -642,7 +672,7 @@
 						      __pa(page->virtual),
 						      0, mask);
 			}
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 			atomic_inc(&dcpage_flushes_xcall);
 #endif
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.16/arch/sparc64/kernel/sparc64_ksyms.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Dec  7 18:48:52 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.116 2001/10/26 15:49:21 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.119 2001/11/30 01:04:10 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -98,7 +98,7 @@
 #ifdef CONFIG_SMP
 extern spinlock_t kernel_flag;
 extern int smp_num_cpus;
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
 extern void _do_spin_lock (spinlock_t *lock, char *str);
 extern void _do_spin_unlock (spinlock_t *lock);
 extern int _spin_trylock (spinlock_t *lock);
@@ -113,7 +113,7 @@
 
 /* used by various drivers */
 #ifdef CONFIG_SMP
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 /* Out of line rw-locking implementation. */
 EXPORT_SYMBOL(__read_lock);
 EXPORT_SYMBOL(__read_unlock);
@@ -145,7 +145,7 @@
 EXPORT_SYMBOL(__cpu_logical_map);
 
 /* Spinlock debugging library, optional. */
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
 EXPORT_SYMBOL(_do_spin_lock);
 EXPORT_SYMBOL(_do_spin_unlock);
 EXPORT_SYMBOL(_spin_trylock);
@@ -319,7 +319,6 @@
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
 EXPORT_SYMBOL(_clear_page);
-EXPORT_SYMBOL(_copy_page);
 EXPORT_SYMBOL(clear_user_page);
 EXPORT_SYMBOL(copy_user_page);
 EXPORT_SYMBOL(__bzero);
@@ -354,4 +353,8 @@
 
 void VISenter(void);
 /* RAID code needs this */
-EXPORT_SYMBOL(VISenter);
+EXPORT_SYMBOL_NOVERS(VISenter);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- linux-2.4.16/arch/sparc64/kernel/sys_sparc.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/sys_sparc.c	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.54 2001/10/28 20:49:13 davem Exp $
+/* $Id: sys_sparc.c,v 1.55 2001/11/29 22:52:03 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -255,27 +255,15 @@
 
 asmlinkage int sparc64_personality(unsigned long personality)
 {
-	unsigned long ret, trying, orig_ret;
+	int ret;
 
-	trying = ret = personality;
-
-	if (current->personality == PER_LINUX32 &&
-	    trying == PER_LINUX)
-		trying = ret = PER_LINUX32;
-
-	/* For PER_LINUX32 we want to retain &default_exec_domain.  */
-	if (trying == PER_LINUX32)
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
 		ret = PER_LINUX;
 
-	orig_ret = ret;
-	ret = sys_personality(ret);
-
-	if (orig_ret == PER_LINUX && trying == PER_LINUX32) {
-		current->personality = PER_LINUX32;
-		ret = PER_LINUX;
-	}
-
-	return (int) ret;
+	return ret;
 }
 
 /* Linux version of mmap */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- linux-2.4.16/arch/sparc64/kernel/time.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/time.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.40 2001/09/06 02:44:28 davem Exp $
+/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -609,7 +609,6 @@
 	unsigned long clock;
 
 	init_timers(timer_interrupt, &clock);
-	timer_tick_offset = clock / HZ;
 	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- linux-2.4.16/arch/sparc64/kernel/trampoline.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/trampoline.S	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.22 2001/09/07 21:04:40 kanoj Exp $
+/* $Id: trampoline.S,v 1.24 2001/11/16 21:59:20 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- linux-2.4.16/arch/sparc64/kernel/traps.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/traps.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.79 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: traps.c,v 1.82 2001/11/18 00:12:56 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -38,16 +38,19 @@
 
 void bad_trap (struct pt_regs *regs, long lvl)
 {
+	char buffer[32];
 	siginfo_t info;
 
 	if (lvl < 0x100) {
-		char buffer[24];
-		
-		sprintf (buffer, "Bad hw trap %lx at tl0\n", lvl);
+		sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
+		die_if_kernel(buffer, regs);
+	}
+
+	lvl -= 0x100;
+	if (regs->tstate & TSTATE_PRIV) {
+		sprintf(buffer, "Kernel bad sw trap %lx", lvl);
 		die_if_kernel (buffer, regs);
 	}
-	if (regs->tstate & TSTATE_PRIV)
-		die_if_kernel ("Kernel bad trap", regs);
 	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
@@ -56,7 +59,7 @@
 	info.si_errno = 0;
 	info.si_code = ILL_ILLTRP;
 	info.si_addr = (void *)regs->tpc;
-	info.si_trapno = lvl - 0x100;
+	info.si_trapno = lvl;
 	force_sig_info(SIGILL, &info, current);
 }
 
@@ -68,6 +71,14 @@
 	die_if_kernel (buffer, regs);
 }
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void do_BUG(const char *file, int line)
+{
+	bust_spinlocks(1);
+	printk("kernel BUG at %s:%d!\n", file, line);
+}
+#endif
+
 void instruction_access_exception (struct pt_regs *regs,
 				   unsigned long sfsr, unsigned long sfar)
 {
@@ -947,6 +958,7 @@
 	__asm__ __volatile__("ldxa	[%0] %3, %%g0\n\t"
 			     "ldxa	[%1] %3, %%g0\n\t"
 			     "casxa	[%2] %3, %%g0, %%g0\n\t"
+			     "membar	#StoreLoad | #StoreStore\n\t"
 			     "ldxa	[%0] %3, %%g0\n\t"
 			     "ldxa	[%1] %3, %%g0\n\t"
 			     "membar	#Sync"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- linux-2.4.16/arch/sparc64/kernel/ttable.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/kernel/ttable.S	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.35 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
  * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -15,11 +15,13 @@
 sparc64_ttable_tl0:
 tl0_resv000:	BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
 tl0_resv004:	BTRAP(0x4)  BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
-tl0_iax:	TRAP_NOSAVE(__do_instruction_access_exception)
+tl0_iax:	membar #Sync
+		TRAP_NOSAVE_7INSNS(__do_instruction_access_exception)
 tl0_resv009:	BTRAP(0x9)
 tl0_iae:	TRAP(do_iae)
 tl0_resv00b:	BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
-tl0_ill:	TRAP(do_illegal_instruction)
+tl0_ill:	membar #Sync
+		TRAP_7INSNS(do_illegal_instruction)
 tl0_privop:	TRAP(do_privop)
 tl0_resv012:	BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
 tl0_resv018:	BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/lib/atomic.S linux/arch/sparc64/lib/atomic.S
--- linux-2.4.16/arch/sparc64/lib/atomic.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/lib/atomic.S	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: atomic.S,v 1.3 2000/03/16 16:44:37 davem Exp $
+/* $Id: atomic.S,v 1.4 2001/11/18 00:12:56 davem Exp $
  * atomic.S: These things are too big to do inline.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -19,7 +19,7 @@
 	cas	[%o1], %g5, %g7
 	cmp	%g5, %g7
 	bne,pn	%icc, __atomic_add
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	retl
 	 add	%g7, %o0, %o0
 
@@ -30,7 +30,7 @@
 	cas	[%o1], %g5, %g7
 	cmp	%g5, %g7
 	bne,pn	%icc, __atomic_sub
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	retl
 	 sub	%g7, %o0, %o0
 atomic_impl_end:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/lib/bitops.S linux/arch/sparc64/lib/bitops.S
--- linux-2.4.16/arch/sparc64/lib/bitops.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/lib/bitops.S	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $
+/* $Id: bitops.S,v 1.3 2001/11/18 00:12:56 davem Exp $
  * bitops.S: Sparc64 atomic bit operations.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -28,7 +28,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_clear_bit
 ___test_and_clear_bit:	/* %o0=nr, %o1=addr */
@@ -47,7 +47,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_change_bit
 ___test_and_change_bit:	/* %o0=nr, %o1=addr */
@@ -65,7 +65,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	nop
 
 	.globl	___test_and_set_le_bit
@@ -85,7 +85,7 @@
 	bne,a,pn %icc, 1b
 	 lduwa	[%o1] ASI_PL, %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_clear_le_bit
 ___test_and_clear_le_bit:	/* %o0=nr, %o1=addr */
@@ -104,7 +104,7 @@
 	bne,a,pn %icc, 1b
 	 lduwa	[%o1] ASI_PL, %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	__bitops_end
 __bitops_end:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- linux-2.4.16/arch/sparc64/lib/blockops.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/lib/blockops.S	Fri Dec  7 18:48:52 2001
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.36 2001/09/24 21:44:03 davem Exp $
+/* $Id: blockops.S,v 1.41 2001/12/05 06:05:35 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -17,10 +17,9 @@
 	fmovd	%reg4, %f56; 	fmovd	%reg5, %f58;		\
 	fmovd	%reg6, %f60; 	fmovd	%reg7, %f62;
 
-#define	TLBTEMP_BASE	(8 * 1024 * 1024)
 #define	DCACHE_SIZE	(PAGE_SIZE * 2)
-#define TLBTEMP_ENT1	(61 << 3)
-#define TLBTEMP_ENT2	(62 << 3)
+#define TLBTEMP_ENT1	(60 << 3)
+#define TLBTEMP_ENT2	(61 << 3)
 #define TLBTEMP_ENTSZ	(1 << 3)
 
 #if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19)
@@ -34,64 +33,6 @@
 	.text
 
 	.align		32
-	.globl		_copy_page
-	.type		_copy_page,@function
-_copy_page: /* %o0=dest, %o1=src */
-	VISEntry
-	membar		#LoadStore | #StoreStore | #StoreLoad
-	ldda		[%o1] ASI_BLK_P, %f0
-	add		%o1, 0x40, %o1
-	ldda		[%o1] ASI_BLK_P, %f16
-	add		%o1, 0x40, %o1
-	sethi		%hi(PAGE_SIZE), %o2
-1:	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
-	ldda		[%o1] ASI_BLK_P, %f32
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
-	ldda		[%o1] ASI_BLK_P, %f0
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
-	ldda		[%o1] ASI_BLK_P, %f16
-	stda		%f48, [%o0] ASI_BLK_P
-	sub		%o2, 0x40, %o2
-	add		%o1, 0x40, %o1
-	cmp		%o2, PAGE_SIZE_REM
-	bne,pt		%xcc, 1b
-	 add		%o0, 0x40, %o0
-#if (PAGE_SHIFT == 16) || (PAGE_SHIFT == 22)
-	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
-	ldda		[%o1] ASI_BLK_P, %f32
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
-	ldda		[%o1] ASI_BLK_P, %f0
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	membar		#Sync
-	stda		%f32, [%o0] ASI_BLK_P
-	add		%o0, 0x40, %o0
-	stda		%f0, [%o0] ASI_BLK_P
-#else
-	membar		#Sync
-	stda		%f0, [%o0] ASI_BLK_P
-	add		%o0, 0x40, %o0
-	stda		%f16, [%o0] ASI_BLK_P
-#endif
-	membar		#Sync
-	VISExit
-	retl
-	 nop
-
 	.globl		copy_user_page
 	.type		copy_user_page,@function
 copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
@@ -110,7 +51,7 @@
 	or		%g2, %g3, %g2
 	add		%o0, %o3, %o0
 	add		%o0, %o1, %o1
-#define FIX_INSN_1	0x96102068 /* mov (13 << 3), %o3 */
+#define FIX_INSN_1	0x96102060 /* mov (12 << 3), %o3 */
 cheetah_patch_1:
 	mov		TLBTEMP_ENT1, %o3
 	rdpr		%pstate, %g3
@@ -134,6 +75,7 @@
 	stxa		%g0, [%o5] ASI_DMMU
 	membar		#Sync
 
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %o5
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
@@ -152,6 +94,7 @@
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o1, [%o2] ASI_DMMU
 	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
@@ -169,9 +112,10 @@
 	 nop
 
 cheetah_copy_user_page:
-	mov		121, %o2			! A0 Group
+	sethi		%hi((PAGE_SIZE/64)-7), %o2	! A0 Group
 	prefetch	[%o1 + 0x000], #one_read	! MS
-	prefetch	[%o1 + 0x040], #one_read	! MS Group
+	or		%o2, %lo((PAGE_SIZE/64)-7), %o2	! A1 Group
+	prefetch	[%o1 + 0x040], #one_read	! MS
 	prefetch	[%o1 + 0x080], #one_read	! MS Group
 	prefetch	[%o1 + 0x0c0], #one_read	! MS Group
 	ldd		[%o1 + 0x000], %f0		! MS Group
@@ -402,7 +346,7 @@
 	or		%g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
 	or		%g1, %g3, %g1
 	add		%o0, %o3, %o0
-#define FIX_INSN_2	0x96102070 /* mov (14 << 3), %o3 */
+#define FIX_INSN_2	0x96102068 /* mov (13 << 3), %o3 */
 cheetah_patch_2:
 	mov		TLBTEMP_ENT2, %o3
 	rdpr		%pstate, %g3
@@ -420,6 +364,7 @@
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
@@ -430,8 +375,9 @@
 clear_page_common:
 	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
 	fzero		%f0				! FPA	Group
-	mov		PAGE_SIZE/256, %o1		! IEU0
+	sethi		%hi(PAGE_SIZE/256), %o1		! IEU0
 	fzero		%f2				! FPA	Group
+	or		%o1, %lo(PAGE_SIZE/256), %o1	! IEU0
 	faddd		%f0, %f2, %f4			! FPA	Group
 	fmuld		%f0, %f2, %f6			! FPM
 	faddd		%f0, %f2, %f8			! FPA	Group
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- linux-2.4.16/arch/sparc64/lib/debuglocks.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/lib/debuglocks.c	Tue Dec  4 19:25:30 2001
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.6 2001/04/24 01:09:12 davem Exp $
+/* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
@@ -10,10 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/system.h>
 
-#ifdef CONFIG_SMP
-
-/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
-#ifdef SPIN_LOCK_DEBUG
+#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
 
 #define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
 
@@ -56,6 +53,7 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 again:
@@ -67,7 +65,8 @@
 	if (val) {
 		while (lock->lock) {
 			if (!--stuck) {
-				show(str, lock, caller);
+				if (shown++ <= 2)
+					show(str, lock, caller);
 				stuck = INIT_STUCK;
 			}
 			membar("#LoadLoad");
@@ -76,6 +75,8 @@
 	}
 	lock->owner_pc = ((unsigned int)caller);
 	lock->owner_cpu = cpu;
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 int _spin_trylock(spinlock_t *lock)
@@ -92,6 +93,8 @@
 	if (!val) {
 		lock->owner_pc = ((unsigned int)caller);
 		lock->owner_cpu = cpu;
+		current->thread.smp_lock_count++;
+		current->thread.smp_lock_pc = ((unsigned int)caller);
 	}
 	return val == 0;
 }
@@ -102,6 +105,7 @@
 	lock->owner_cpu = NO_PROC_ID;
 	membar("#StoreStore | #LoadStore");
 	lock->lock = 0;
+	current->thread.smp_lock_count--;
 }
 
 /* Keep INIT_STUCK the same... */
@@ -111,13 +115,15 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 wlock_again:
 	/* Wait for any writer to go away.  */
 	while (((long)(rw->lock)) < 0) {
 		if (!--stuck) {
-			show_read(str, rw, caller);
+			if (shown++ <= 2)
+				show_read(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		membar("#LoadLoad");
@@ -137,6 +143,8 @@
 	if (val)
 		goto wlock_again;
 	rw->reader_pc[cpu] = ((unsigned int)caller);
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 void _do_read_unlock (rwlock_t *rw, char *str)
@@ -144,11 +152,13 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 
 	/* Drop our identity _first_. */
 	rw->reader_pc[cpu] = 0;
+	current->thread.smp_lock_count--;
 runlock_again:
 	/* Spin trying to decrement the counter using casx.  */
 	__asm__ __volatile__(
@@ -162,7 +172,8 @@
 	: "g5", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
-			show_read(str, rw, caller);
+			if (shown++ <= 2)
+				show_read(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto runlock_again;
@@ -174,13 +185,15 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 wlock_again:
 	/* Spin while there is another writer. */
 	while (((long)rw->lock) < 0) {
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		membar("#LoadLoad");
@@ -204,7 +217,8 @@
 	if (val) {
 		/* We couldn't get the write bit. */
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto wlock_again;
@@ -214,7 +228,8 @@
 		 * lock, spin, and try again.
 		 */
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		__asm__ __volatile__(
@@ -231,7 +246,8 @@
 		: "g3", "g5", "g7", "cc", "memory");
 		while(rw->lock != 0) {
 			if (!--stuck) {
-				show_write(str, rw, caller);
+				if (shown++ <= 2)
+					show_write(str, rw, caller);
 				stuck = INIT_STUCK;
 			}
 			membar("#LoadLoad");
@@ -242,18 +258,22 @@
 	/* We have it, say who we are. */
 	rw->writer_pc = ((unsigned int)caller);
 	rw->writer_cpu = cpu;
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 void _do_write_unlock(rwlock_t *rw)
 {
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
+	int shown = 0;
 
 	GET_CALLER(caller);
 
 	/* Drop our identity _first_ */
 	rw->writer_pc = 0;
 	rw->writer_cpu = NO_PROC_ID;
+	current->thread.smp_lock_count--;
 wlock_again:
 	__asm__ __volatile__(
 "	mov	1, %%g3\n"
@@ -268,12 +288,21 @@
 	: "g3", "g5", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
-			show_write("write_unlock", rw, caller);
+			if (shown++ <= 2)
+				show_write("write_unlock", rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto wlock_again;
 	}
 }
 
-#endif /* SPIN_LOCK_DEBUG */
-#endif /* CONFIG_SMP */
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	spin_unlock(lock);
+	return 0;
+}
+
+#endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/lib/dec_and_lock.S linux/arch/sparc64/lib/dec_and_lock.S
--- linux-2.4.16/arch/sparc64/lib/dec_and_lock.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/lib/dec_and_lock.S	Tue Dec  4 19:25:30 2001
@@ -1,10 +1,12 @@
-/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $
+/* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $
  * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()"
  *                 using cas and ldstub instructions.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
  */
+#include <linux/config.h>
 
+#ifndef CONFIG_DEBUG_SPINLOCK
 	.text
 	.align	64
 
@@ -34,13 +36,15 @@
 	bne,pn	%icc, loop1
 	 mov	0, %g1
 
-out:	retl
+out:
+	membar	#StoreLoad | #StoreStore
+	retl
 	 mov	%g1, %o0
-to_zero:ldstub	[%o1], %g3
+to_zero:
+	ldstub	[%o1], %g3
 	brnz,pn	%g3, spin_on_lock
 	 membar	#StoreLoad | #StoreStore
 loop2:	cas	[%o0], %g5, %g7		/* ASSERT(g7 == 0) */
-	nop
 	cmp	%g5, %g7
 
 	be,pt	%icc, out
@@ -61,3 +65,5 @@
 	ba,pt	%xcc, to_zero
 	 nop
 	nop
+
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/mm/extable.c linux/arch/sparc64/mm/extable.c
--- linux-2.4.16/arch/sparc64/mm/extable.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/mm/extable.c	Tue Dec  4 19:25:30 2001
@@ -11,35 +11,49 @@
 
 static unsigned long
 search_one_table(const struct exception_table_entry *start,
-		 const struct exception_table_entry *last,
+		 const struct exception_table_entry *end,
 		 unsigned long value, unsigned long *g2)
 {
-	const struct exception_table_entry *first = start;
-	const struct exception_table_entry *mid;
-	long diff = 0;
-        while (first <= last) {
-		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0) {
-                	if (!mid->fixup) {
-                		*g2 = 0;
-                		return (mid + 1)->fixup;
-                	} else
-	                        return mid->fixup;
-                } else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        if (last->insn < value && !last->fixup && last[1].insn > value) {
-        	*g2 = (value - last->insn)/4;
-        	return last[1].fixup;
-        }
-        if (first > start && first[-1].insn < value
-	    && !first[-1].fixup && first->insn < value) {
-        	*g2 = (value - first[-1].insn)/4;
-        	return first->fixup;
-        }
+	const struct exception_table_entry *walk;
+
+	/* Single insn entries are encoded as:
+	 *	word 1:	insn address
+	 *	word 2:	fixup code address
+	 *
+	 * Range entries are encoded as:
+	 *	word 1: first insn address
+	 *	word 2: 0
+	 *	word 3: last insn address + 4 bytes
+	 *	word 4: fixup code address
+	 *
+	 * See asm/uaccess.h for more details.
+	 */
+
+	/* 1. Try to find an exact match. */
+	for (walk = start; walk <= end; walk++) {
+		if (walk->fixup == 0) {
+			/* A range entry, skip both parts. */
+			walk++;
+			continue;
+		}
+
+		if (walk->insn == value)
+			return walk->fixup;
+	}
+
+	/* 2. Try to find a range match. */
+	for (walk = start; walk <= (end - 1); walk++) {
+		if (walk->fixup)
+			continue;
+
+		if (walk[0].insn <= value &&
+		    walk[1].insn > value) {
+			*g2 = (value - walk[0].insn) / 4;
+			return walk[1].fixup;
+		}
+		walk++;
+	}
+
         return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- linux-2.4.16/arch/sparc64/mm/init.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/mm/init.c	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.202 2001/11/13 00:49:28 davem Exp $
+/*  $Id: init.c,v 1.207 2001/11/30 06:55:39 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -63,6 +63,8 @@
 
 struct page *mem_map_zero;
 
+int bigkernel = 0;
+
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
@@ -111,7 +113,7 @@
 
 extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 atomic_t dcpage_flushes = ATOMIC_INIT(0);
 #ifdef CONFIG_SMP
 atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0);
@@ -120,7 +122,7 @@
 
 __inline__ void flush_dcache_page_impl(struct page *page)
 {
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes);
 #endif
 
@@ -152,7 +154,7 @@
 			     "casx	[%2], %%g7, %%g5\n\t"
 			     "cmp	%%g7, %%g5\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " nop"
+			     " membar	#StoreLoad | #StoreStore"
 			     : /* no outputs */
 			     : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
 			     : "g5", "g7");
@@ -172,7 +174,7 @@
 			     "casx	[%2], %%g7, %%g5\n\t"
 			     "cmp	%%g7, %%g5\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " nop\n"
+			     " membar	#StoreLoad | #StoreStore\n"
 			     "2:"
 			     : /* no outputs */
 			     : "r" (cpu), "r" (mask), "r" (&page->flags)
@@ -261,14 +263,14 @@
 	else
 		seq_printf(m, "MMU Type\t: ???\n");
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 	seq_printf(m, "DCPageFlushes\t: %d\n",
 		   atomic_read(&dcpage_flushes));
 #ifdef CONFIG_SMP
 	seq_printf(m, "DCPageFlushesXC\t: %d\n",
 		   atomic_read(&dcpage_flushes_xcall));
 #endif /* CONFIG_SMP */
-#endif /* DCFLUSH_DEBUG */
+#endif /* CONFIG_DEBUG_DCFLUSH */
 }
 
 struct linux_prom_translation {
@@ -505,6 +507,10 @@
 		   (unsigned long) KERNBASE,
 		   prom_get_mmu_ihandle());
 
+	if (bigkernel)
+		remap_func(((tte_data + 0x400000) & _PAGE_PADDR),
+			(unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle());
+
 	/* Flush out that temporary mapping. */
 	spitfire_flush_dtlb_nucleus_page(0x0);
 	spitfire_flush_itlb_nucleus_page(0x0);
@@ -512,6 +518,12 @@
 	/* Now lock us back into the TLBs via OBP. */
 	prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
 	prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
+	if (bigkernel) {
+		prom_dtlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, 
+								tte_vaddr + 0x400000);
+		prom_itlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, 
+								tte_vaddr + 0x400000);
+	}
 
 	/* Re-read translations property. */
 	if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
@@ -528,6 +540,8 @@
 			unsigned long avoid_start = (unsigned long) KERNBASE;
 			unsigned long avoid_end = avoid_start + (4 * 1024 * 1024);
 
+			if (bigkernel)
+				avoid_end += (4 * 1024 * 1024);
 			if (vaddr < avoid_start) {
 				unsigned long top = vaddr + size;
 
@@ -714,7 +728,8 @@
 		}
 	}
 	if (tlb_type == spitfire) {
-		for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) {
+		int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel;
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
@@ -752,7 +767,7 @@
 			}
 		}
 
-		for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) {
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
@@ -790,7 +805,9 @@
 			}
 		}
 	} else if (tlb_type == cheetah) {
-		for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) {
+		int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
+
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			data = cheetah_get_ldtlb_data(i);
@@ -814,7 +831,7 @@
 			}
 		}
 
-		for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) {
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			data = cheetah_get_litlb_data(i);
@@ -1282,6 +1299,8 @@
 	set_bit(0, mmu_context_bmap);
 
 	real_end = (unsigned long)&_end;
+	if ((real_end > ((unsigned long)KERNBASE + 0x400000)))
+		bigkernel = 1;
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (sparc_ramdisk_image)
 		real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c
--- linux-2.4.16/arch/sparc64/mm/modutil.c	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/mm/modutil.c	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/*  $Id: modutil.c,v 1.9 2001/08/14 22:10:56 davem Exp $
+/*  $Id: modutil.c,v 1.11 2001/12/05 06:05:35 davem Exp $
  *  arch/sparc64/mm/modutil.c
  *
  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -10,10 +10,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-
-#define  MODULES_VADDR	0x0000000001000000ULL  /* Where to map modules */
-#define  MODULES_LEN	0x000000007f000000ULL
-#define  MODULES_END	0x0000000080000000ULL
 
 static struct vm_struct * modvmlist = NULL;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- linux-2.4.16/arch/sparc64/mm/ultra.S	Mon Nov 26 10:35:04 2001
+++ linux/arch/sparc64/mm/ultra.S	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.68 2001/11/09 14:59:19 davem Exp $
+/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -117,7 +117,7 @@
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
 	/* XXX Spitfire dependency... */
-	mov		(62 << 3), %g2
+	mov		((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
 
 	/* Spitfire Errata #32 workaround. */
 	mov		0x8, %o4
@@ -642,7 +642,7 @@
 	stx		%g0, [%g4 + %lo(errata32_hwbug)]
 
 2:	add		%g2, 1, %g2
-	cmp		%g2, 63
+	cmp		%g2, SPITFIRE_HIGHEST_LOCKED_TLBENT
 	ble,pt		%icc, 1b
 	 sll		%g2, 3, %g3
 	flush		%g6
@@ -679,20 +679,15 @@
 
 	.globl		xcall_call_function
 xcall_call_function:
-	mov		TLB_TAG_ACCESS, %g5		! wheee...
-	stxa		%g1, [%g5] ASI_IMMU		! save call_data here for a bit
-	membar		#Sync
 	rdpr		%pstate, %g2
 	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
-	mov		TLB_TAG_ACCESS, %g2
-	ldxa		[%g2] ASI_IMMU, %g5
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	call		smp_call_function_client
-	 mov		%l5, %o0
+	 nop
 	b,pt		%xcc, rtrap
 	 clr		%l6
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/atm/eni.c linux/drivers/atm/eni.c
--- linux-2.4.16/drivers/atm/eni.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/atm/eni.c	Fri Dec  7 18:08:43 2001
@@ -2310,7 +2310,7 @@
 	name:		DEV_LABEL,
 	id_table:	eni_pci_tbl,
 	probe:		eni_init_one,
-	remove:		eni_remove_one,
+	remove:		__devexit_p(eni_remove_one),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/atm/firestream.c linux/drivers/atm/firestream.c
--- linux-2.4.16/drivers/atm/firestream.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/atm/firestream.c	Fri Dec  7 18:08:43 2001
@@ -2102,7 +2102,7 @@
 	name:           "firestream",
 	id_table:       firestream_pci_tbl,
 	probe:          firestream_init_one,
-	remove:         firestream_remove_one,
+	remove:         __devexit_p(firestream_remove_one),
 };
 
 static int __init firestream_init_module (void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/atm/idt77252.c linux/drivers/atm/idt77252.c
--- linux-2.4.16/drivers/atm/idt77252.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/atm/idt77252.c	Tue Dec  4 19:25:30 2001
@@ -1,8 +1,8 @@
 /******************************************************************* 
- * ident "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $"
+ * ident "$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $"
  *
  * $Author: ecd $
- * $Date: 2001/11/11 08:13:54 $
+ * $Date: 2001/11/17 00:30:19 $
  *
  * Copyright (c) 2000 ATecoM GmbH 
  *
@@ -30,7 +30,7 @@
  *
  *******************************************************************/
 static char const rcsid[] =
-"$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $";
+"$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $";
 
 
 #include <linux/module.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/cciss.c linux/drivers/block/cciss.c
--- linux-2.4.16/drivers/block/cciss.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/cciss.c	Fri Dec  7 18:08:43 2001
@@ -2019,7 +2019,7 @@
 static struct pci_driver cciss_pci_driver = {
 	 name:   "cciss",
 	probe:  cciss_init_one,
-	remove:  cciss_remove_one,
+	remove:  __devexit_p(cciss_remove_one),
 	id_table:  cciss_pci_device_id, /* id_table */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/floppy.c linux/drivers/block/floppy.c
--- linux-2.4.16/drivers/block/floppy.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/floppy.c	Thu Dec  6 16:28:10 2001
@@ -4498,3 +4498,5 @@
 	}
 }
 #endif
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/loop.c linux/drivers/block/loop.c
--- linux-2.4.16/drivers/block/loop.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/loop.c	Wed Dec  5 20:24:17 2001
@@ -640,6 +640,10 @@
 
 	if (S_ISBLK(inode->i_mode)) {
 		lo_device = inode->i_rdev;
+		if (lo_device == dev) {
+			error = -EBUSY;
+			goto out;
+		}
 	} else if (S_ISREG(inode->i_mode)) {
 		struct address_space_operations *aops = inode->i_mapping->a_ops;
 		/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/nbd.c linux/drivers/block/nbd.c
--- linux-2.4.16/drivers/block/nbd.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/nbd.c	Mon Dec 10 18:45:06 2001
@@ -45,7 +45,6 @@
 
 #include <linux/devfs_fs_kernel.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/types.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- linux-2.4.16/drivers/block/paride/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/paride/Config.in	Fri Dec  7 19:41:06 2001
@@ -29,7 +29,7 @@
 dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
 if [ "$CONFIG_PARIDE_EPAT" != "n" ]; then
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool '     Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8 $CONFIG_PARIDE
+    bool '     Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8
   fi
 fi
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- linux-2.4.16/drivers/block/paride/pf.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/paride/pf.c	Thu Dec  6 16:17:22 2001
@@ -733,7 +733,8 @@
 	for (k=0;k<len;k++) 
 	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
 		l=targ[j++]=buf[k+offs];
-	if (l==0x20) j--; targ[j]=0;
+	if (l==0x20) j--;
+	targ[j]=0;
 }
 
 static int xl( char *buf, int offs )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- linux-2.4.16/drivers/block/paride/pg.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/paride/pg.c	Thu Dec  6 16:17:22 2001
@@ -491,7 +491,8 @@
 	for (k=0;k<len;k++) 
 	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
 		l=targ[j++]=buf[k+offs];
-	if (l==0x20) j--; targ[j]=0;
+	if (l==0x20) j--;
+	targ[j]=0;
 }
 
 static int pg_identify( int unit, int log )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- linux-2.4.16/drivers/block/paride/pseudo.h	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/paride/pseudo.h	Thu Dec  6 16:12:19 2001
@@ -102,7 +102,7 @@
 		spin_unlock_irqrestore(&ps_spinlock,flags);
 		return;
 	}
-        if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
+        if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
                 ps_continuation = NULL;
         	spin_unlock_irqrestore(&ps_spinlock,flags);
                 con();
@@ -131,7 +131,7 @@
 	        spin_unlock_irqrestore(&ps_spinlock,flags);
 		return;
 	}
-        if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
+        if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
                 ps_continuation = NULL;
 	        spin_unlock_irqrestore(&ps_spinlock,flags);
                 con();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- linux-2.4.16/drivers/block/paride/pt.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/paride/pt.c	Thu Dec  6 16:17:22 2001
@@ -577,7 +577,8 @@
 	for (k=0;k<len;k++) 
 	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
 		l=targ[j++]=buf[k+offs];
-	if (l==0x20) j--; targ[j]=0;
+	if (l==0x20) j--;
+	targ[j]=0;
 }
 
 static int xn( char *buf, int offs, int size )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/block/rd.c linux/drivers/block/rd.c
--- linux-2.4.16/drivers/block/rd.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/block/rd.c	Tue Dec  4 19:25:30 2001
@@ -110,7 +110,7 @@
  */
 int rd_size = CONFIG_BLK_DEV_RAM_SIZE;		/* Size of the RAM disks */
 /*
- * It would be very desiderable to have a soft-blocksize (that in the case
+ * It would be very desirable to have a soft-blocksize (that in the case
  * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because
  * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of
  * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- linux-2.4.16/drivers/char/agp/agpgart_be.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/agp/agpgart_be.c	Sun Dec  9 18:13:45 2001
@@ -409,8 +409,18 @@
 	 *        AGP devices and collect their data.
 	 */
 
-	while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
-					device)) != NULL) {
+
+	pci_for_each_dev(device)
+	{
+		/*
+		 *	Enable AGP devices. Most will be VGA display but
+		 *	some may be coprocessors on non VGA devices too
+		 */
+		 
+		if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
+			(device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
+			continue;
+
 		pci_read_config_dword(device, 0x04, &scratch);
 
 		if (!(scratch & 0x00100000))
@@ -3242,8 +3252,18 @@
 	 *        AGP devices and collect their data.
 	 */
 
-	while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
-					device)) != NULL) {
+
+	pci_for_each_dev(device)
+	{
+		/*
+		 *	Enable AGP devices. Most will be VGA display but
+		 *	some may be coprocessors on non VGA devices too
+		 */
+		 
+		if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
+			(device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
+			continue;
+
 		pci_read_config_dword(device, 0x04, &scratch);
 
 		if (!(scratch & 0x00100000))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/console.c linux/drivers/char/console.c
--- linux-2.4.16/drivers/char/console.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/console.c	Mon Dec 10 18:36:50 2001
@@ -2599,10 +2599,10 @@
 
 static void set_vesa_blanking(unsigned long arg)
 {
-    char *argp = (char *)arg + 1;
-    unsigned int mode;
-    get_user(mode, argp);
-    vesa_blank_mode = (mode < 4) ? mode : 0;
+	char *argp = (char *)arg + 1;
+	unsigned int mode;
+	if (get_user(mode, argp) == 0)
+		vesa_blank_mode = (mode < 4) ? mode : 0;
 }
 
 /* We can't register the console with devfs during con_init(), because it
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/Config.in linux/drivers/char/drm/Config.in
--- linux-2.4.16/drivers/char/drm/Config.in	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/drm/Config.in	Fri Dec  7 19:20:42 2001
@@ -13,4 +13,5 @@
     dep_tristate '  ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP
     dep_tristate '  Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
     dep_tristate '  Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
+    dep_tristate '  SiS' CONFIG_DRM_SIS $CONFIG_AGP
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/Makefile linux/drivers/char/drm/Makefile
--- linux-2.4.16/drivers/char/drm/Makefile	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/drm/Makefile	Fri Dec  7 19:20:42 2001
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 O_TARGET	:= drm.o
-list-multi	:= gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o
+list-multi	:= gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o
 
 gamma-objs  := gamma_drv.o gamma_dma.o
 tdfx-objs   := tdfx_drv.o
@@ -12,6 +12,7 @@
 i810-objs   := i810_drv.o i810_dma.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o
 ffb-objs    := ffb_drv.o ffb_context.o
+sis-objs    := sis_drv.o sis_ds.o sis_mm.o
 
 obj-$(CONFIG_DRM_GAMMA) += gamma.o
 obj-$(CONFIG_DRM_TDFX)	+= tdfx.o
@@ -20,6 +21,7 @@
 obj-$(CONFIG_DRM_MGA)	+= mga.o
 obj-$(CONFIG_DRM_I810)	+= i810.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
+obj-$(CONFIG_DRM_SIS)   += sis.o
 
 include $(TOPDIR)/Rules.make
 
@@ -43,3 +45,6 @@
 
 ffb.o: $(ffb-objs) $(lib)
 	$(LD) -r -o $@ $(ffb-objs) $(lib)
+
+sis.o: $(sis-objs) $(lib)
+	$(LD) -r -o $@ $(sis-objs) $(lib)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/drm.h linux/drivers/char/drm/drm.h
--- linux-2.4.16/drivers/char/drm/drm.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/drm/drm.h	Fri Dec  7 19:20:42 2001
@@ -104,7 +104,7 @@
 #include "i810_drm.h"
 #include "r128_drm.h"
 #include "radeon_drm.h"
-#ifdef CONFIG_DRM_SIS
+#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE)
 #include "sis_drm.h"
 #endif
 
@@ -483,7 +483,7 @@
 #define DRM_IOCTL_RADEON_INDIRECT	DRM_IOWR(0x4d, drm_radeon_indirect_t)
 #define DRM_IOCTL_RADEON_TEXTURE	DRM_IOWR(0x4e, drm_radeon_texture_t)
 
-#ifdef CONFIG_DRM_SIS
+#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE)
 /* SiS specific ioctls */
 #define SIS_IOCTL_FB_ALLOC		DRM_IOWR(0x44, drm_sis_mem_t)
 #define SIS_IOCTL_FB_FREE		DRM_IOW( 0x45, drm_sis_mem_t)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/drm_context.h linux/drivers/char/drm/drm_context.h
--- linux-2.4.16/drivers/char/drm/drm_context.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/drm/drm_context.h	Fri Dec  7 19:20:42 2001
@@ -27,6 +27,10 @@
  * Authors:
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
+ * ChangeLog:
+ *  2001-11-16	Torsten Duwe <duwe@caldera.de>
+ *		added context constructor/destructor hooks,
+ *		needed by SiS driver's memory management.
  */
 
 #define __NO_VERSION__
@@ -316,6 +320,10 @@
 				/* Should this return -EBUSY instead? */
 		return -ENOMEM;
 	}
+#ifdef DRIVER_CTX_CTOR
+	if ( ctx.handle != DRM_KERNEL_CONTEXT )
+		DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */
+#endif
 
 	if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) )
 		return -EFAULT;
@@ -390,6 +398,9 @@
 		priv->remove_auth_on_close = 1;
 	}
 	if ( ctx.handle != DRM_KERNEL_CONTEXT ) {
+#ifdef DRIVER_CTX_DTOR
+		DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */
+#endif
 		DRM(ctxbitmap_free)( dev, ctx.handle );
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis.h linux/drivers/char/drm/sis.h
--- linux-2.4.16/drivers/char/drm/sis.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis.h	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,56 @@
+/* sis_drv.h -- Private header for sis driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.1 2001/05/19 18:29:22 dawes Exp $ */
+
+#ifndef __SIS_H__
+#define __SIS_H__
+
+/* This remains constant for all DRM template files.
+ * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel
+ * that's used for fb devices 
+ */
+#define DRM(x) sisdrv_##x
+
+/* General customization:
+ */
+#define __HAVE_AGP		1
+#define __MUST_HAVE_AGP		0
+#define __HAVE_MTRR		1
+#define __HAVE_CTX_BITMAP	1
+
+/* Buffer customization:
+ */
+#define DRIVER_AGP_BUFFERS_MAP( dev )					\
+	((drm_sis_private_t *)((dev)->dev_private))->buffers
+
+extern int sis_init_context(int context);
+extern int sis_final_context(int context);
+
+#define DRIVER_CTX_CTOR sis_init_context
+#define DRIVER_CTX_DTOR sis_final_context
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis_drm.h linux/drivers/char/drm/sis_drm.h
--- linux-2.4.16/drivers/char/drm/sis_drm.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis_drm.h	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,36 @@
+
+#ifndef _sis_drm_public_h_
+#define _sis_drm_public_h_
+
+typedef struct {
+  int context;
+  unsigned int offset;
+  unsigned int size;
+  unsigned int free;
+} drm_sis_mem_t;
+
+typedef struct {
+  unsigned int offset, size;
+} drm_sis_agp_t;
+
+typedef struct {
+  unsigned int left, right;
+} drm_sis_flip_t;
+
+#ifdef __KERNEL__
+
+int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+
+int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis_drv.c linux/drivers/char/drm/sis_drv.c
--- linux-2.4.16/drivers/char/drm/sis_drv.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis_drv.c	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,74 @@
+/* sis.c -- sis driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/config.h>
+#include "sis.h"
+#include "drmP.h"
+#include "sis_drm.h"
+#include "sis_drv.h"
+
+#define DRIVER_AUTHOR	 "SIS"
+#define DRIVER_NAME	 "sis"
+#define DRIVER_DESC	 "SIS 300/630/540"
+#define DRIVER_DATE	 "20010503"
+#define DRIVER_MAJOR	 1
+#define DRIVER_MINOR	 0
+#define DRIVER_PATCHLEVEL  0
+
+#define DRIVER_IOCTLS \
+        [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)]   = { sis_fb_alloc,	  1, 1 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)]    = { sis_fb_free,	  1, 1 }, \
+        /* AGP Memory Management */					  \
+        [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)]   = { sisp_agp_init,	  1, 1 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)]  = { sisp_agp_alloc,  1, 1 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)]   = { sisp_agp_free,	  1, 1 }
+#if 0 /* these don't appear to be defined */
+	/* SIS Stereo */						 
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]    = { sis_control,	  1, 1 }, 
+        [DRM_IOCTL_NR(SIS_IOCTL_FLIP)]       = { sis_flip,	  1, 1 }, 
+        [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)]  = { sis_flip_init,	  1, 1 }, 
+        [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final,  1, 1 }
+#endif
+
+#define __HAVE_COUNTERS		5
+
+#include "drm_auth.h"
+#include "drm_agpsupport.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_drv.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lists.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis_drv.h linux/drivers/char/drm/sis_drv.h
--- linux-2.4.16/drivers/char/drm/sis_drv.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis_drv.h	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,45 @@
+/* sis_drv.h -- Private header for sis driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */
+
+#ifndef _SIS_DRV_H_
+#define _SIS_DRV_H_
+
+typedef struct drm_sis_private {
+	drm_map_t *buffers;
+} drm_sis_private_t;
+
+/* Stereo ? - this was never committed */
+
+int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg);
+void flip_final(void);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis_ds.c linux/drivers/char/drm/sis_ds.c
--- linux-2.4.16/drivers/char/drm/sis_ds.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis_ds.c	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,406 @@
+/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
+ *
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Sung-Ching Lin <sclin@sis.com.tw>
+ * 
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+
+#include "sis_ds.h"
+
+/* Set Data Structure, not check repeated value
+ * temporarily used
+ */
+
+set_t *setInit(void)
+{
+  int i;
+  set_t *set;
+
+  set = (set_t *)MALLOC(sizeof(set_t));
+  for(i = 0; i < SET_SIZE; i++){
+    set->list[i].free_next = i+1;    
+    set->list[i].alloc_next = -1;
+  }    
+  set->list[SET_SIZE-1].free_next = -1;
+  set->free = 0;
+  set->alloc = -1;
+  set->trace = -1;
+  
+  return set;
+}
+
+int setAdd(set_t *set, ITEM_TYPE item)
+{
+  int free = set->free;
+  
+  if(free != -1){
+    set->list[free].val = item;
+    set->free = set->list[free].free_next;
+  }
+  else{
+    return 0;
+  }
+
+  set->list[free].alloc_next = set->alloc;
+  set->alloc = free;  
+  set->list[free].free_next = -1;    
+
+  return 1;
+}
+
+int setDel(set_t *set, ITEM_TYPE item)
+{
+  int alloc = set->alloc;
+  int prev = -1;  
+  
+  while(alloc != -1){
+    if(set->list[alloc].val == item){
+      if(prev != -1)      
+        set->list[prev].alloc_next = set->list[alloc].alloc_next; 
+      else
+        set->alloc = set->list[alloc].alloc_next;
+      break;
+    }
+    prev = alloc;
+    alloc = set->list[alloc].alloc_next;      
+  }
+
+  if(alloc == -1)
+    return 0;
+  
+  set->list[alloc].free_next = set->free;
+  set->free = alloc;
+  set->list[alloc].alloc_next = -1;   
+
+  return 1;
+}
+
+/* setFirst -> setAdd -> setNext is wrong */
+
+int setFirst(set_t *set, ITEM_TYPE *item)
+{
+  if(set->alloc == -1)
+    return 0;
+
+  *item = set->list[set->alloc].val;
+  set->trace = set->list[set->alloc].alloc_next; 
+
+  return 1;
+}
+
+int setNext(set_t *set, ITEM_TYPE *item)
+{
+  if(set->trace == -1)
+    return 0;
+  
+  *item = set->list[set->trace].val;
+  set->trace = set->list[set->trace].alloc_next;      
+
+  return 1;
+}
+
+int setDestroy(set_t *set)
+{
+  FREE(set);
+
+  return 1;
+}
+
+/*
+ * GLX Hardware Device Driver common code
+ * Copyright (C) 1999 Keith Whitwell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define ISFREE(bptr) ((bptr)->free)
+
+#define PRINTF(fmt, arg...) do{}while(0)
+#define fprintf(fmt, arg...) do{}while(0)
+
+static void *calloc(size_t nmemb, size_t size)
+{
+  void *addr;
+  addr = kmalloc(nmemb*size, GFP_KERNEL);
+  memset(addr, 0, nmemb*size);
+  return addr;
+}
+#define free(n) kfree(n)
+           
+void mmDumpMemInfo( memHeap_t *heap )
+{
+  TMemBlock *p;
+
+  PRINTF ("Memory heap %p:\n", heap);
+  if (heap == 0) {
+    PRINTF ("  heap == 0\n");
+  } else {
+    p = (TMemBlock *)heap;
+    while (p) {
+      PRINTF ("  Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
+	     p->free ? '.':'U',
+	     p->reserved ? 'R':'.');
+      p = p->next;
+    }
+  }
+  PRINTF ("End of memory blocks\n");
+}
+
+memHeap_t *mmInit(int ofs,
+		  int size)
+{
+   PMemBlock blocks;
+  
+   if (size <= 0) {
+      return 0;
+   }
+   blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock));
+   if (blocks) {
+      blocks->ofs = ofs;
+      blocks->size = size;
+      blocks->free = 1;
+      return (memHeap_t *)blocks;
+   } else
+      return 0;
+}
+
+/* Kludgey workaround for existing i810 server.  Remove soon.
+ */
+memHeap_t *mmAddRange( memHeap_t *heap,
+		       int ofs,
+		       int size )
+{
+   PMemBlock blocks;
+   blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock));
+   if (blocks) {
+      blocks[0].size = size;
+      blocks[0].free = 1;
+      blocks[0].ofs = ofs;
+      blocks[0].next = &blocks[1];
+
+      /* Discontinuity - stops JoinBlock from trying to join non-adjacent
+       * ranges.
+       */
+      blocks[1].size = 0;
+      blocks[1].free = 0;
+      blocks[1].ofs = ofs+size;
+      blocks[1].next = (PMemBlock) heap;      
+      return (memHeap_t *)blocks;
+   } 
+   else
+      return heap;
+}
+
+static TMemBlock* SliceBlock(TMemBlock *p, 
+			     int startofs, int size, 
+			     int reserved, int alignment)
+{
+  TMemBlock *newblock;
+
+  /* break left */
+  if (startofs > p->ofs) {
+    newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock));
+    newblock->ofs = startofs;
+    newblock->size = p->size - (startofs - p->ofs);
+    newblock->free = 1;
+    newblock->next = p->next;
+    p->size -= newblock->size;
+    p->next = newblock;
+    p = newblock;
+  }
+
+  /* break right */
+  if (size < p->size) {
+    newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock));
+    newblock->ofs = startofs + size;
+    newblock->size = p->size - size;
+    newblock->free = 1;
+    newblock->next = p->next;
+    p->size = size;
+    p->next = newblock;
+  }
+
+  /* p = middle block */
+  p->align = alignment;
+  p->free = 0;
+  p->reserved = reserved;
+  return p;
+}
+
+PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch)
+{
+  int mask,startofs,endofs;
+  TMemBlock *p;
+
+  if (!heap || align2 < 0 || size <= 0)
+    return NULL;
+  mask = (1 << align2)-1;
+  startofs = 0;
+  p = (TMemBlock *)heap;
+  while (p) {
+    if (ISFREE(p)) {
+      startofs = (p->ofs + mask) & ~mask;
+      if ( startofs < startSearch ) {
+      	startofs = startSearch;
+      }
+      endofs = startofs+size;
+      if (endofs <= (p->ofs+p->size))
+	break;
+    }
+    p = p->next;
+  }
+  if (!p)
+    return NULL;
+  p = SliceBlock(p,startofs,size,0,mask+1);
+  p->heap = heap;
+  return p;
+}
+
+static __inline__ int Join2Blocks(TMemBlock *p)
+{
+  if (p->free && p->next && p->next->free) {
+    TMemBlock *q = p->next;
+    p->size += q->size;
+    p->next = q->next;
+    free(q);
+    return 1;
+  }
+  return 0;
+}
+
+int mmFreeMem(PMemBlock b)
+{
+  TMemBlock *p,*prev;
+
+  if (!b)
+    return 0;
+  if (!b->heap) {
+     fprintf(stderr, "no heap\n");
+     return -1;
+  }
+  p = b->heap;
+  prev = NULL;
+  while (p && p != b) {
+    prev = p;
+    p = p->next;
+  }
+  if (!p || p->free || p->reserved) {
+     if (!p)
+	fprintf(stderr, "block not found in heap\n");
+     else if (p->free)
+	fprintf(stderr, "block already free\n");
+     else
+	fprintf(stderr, "block is reserved\n");
+    return -1;
+  }
+  p->free = 1;
+  Join2Blocks(p);
+  if (prev)
+    Join2Blocks(prev);
+  return 0;
+}
+
+int mmReserveMem(memHeap_t *heap, int offset,int size)
+{
+  int endofs;
+  TMemBlock *p;
+
+  if (!heap || size <= 0)
+    return -1;
+  endofs = offset+size;
+  p = (TMemBlock *)heap;
+  while (p && p->ofs <= offset) {
+    if (ISFREE(p) && endofs <= (p->ofs+p->size)) {
+      SliceBlock(p,offset,size,1,1);
+      return 0;
+    }
+    p = p->next;
+  }
+  return -1;
+}
+
+int mmFreeReserved(memHeap_t *heap, int offset)
+{
+  TMemBlock *p,*prev;
+
+  if (!heap)
+    return -1;
+  p = (TMemBlock *)heap;
+  prev = NULL;
+  while (p && p->ofs != offset) {
+    prev = p;
+    p = p->next;
+  }
+  if (!p || !p->reserved)
+    return -1;
+  p->free = 1;
+  p->reserved = 0;
+  Join2Blocks(p);
+  if (prev)
+    Join2Blocks(prev);
+  return 0;
+}
+
+void mmDestroy(memHeap_t *heap)
+{
+  TMemBlock *p,*q;
+
+  if (!heap)
+    return;
+  p = (TMemBlock *)heap;
+  while (p) {
+    q = p->next;
+    free(p);
+    p = q;
+  }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis_ds.h linux/drivers/char/drm/sis_ds.h
--- linux-2.4.16/drivers/char/drm/sis_ds.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis_ds.h	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,163 @@
+/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
+ *
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Sung-Ching Lin <sclin@sis.com.tw>
+ * 
+ */
+
+#ifndef _sis_ds_h_
+#define _sis_ds_h_
+
+/* Set Data Structure */
+
+#define SET_SIZE 5000
+#define MALLOC(s) kmalloc(s, GFP_KERNEL)
+#define FREE(s) kfree(s)
+
+typedef unsigned int ITEM_TYPE;
+
+typedef struct {
+  ITEM_TYPE val;
+  int alloc_next, free_next;
+} list_item_t;
+
+typedef struct {
+  int alloc;
+  int free;
+  int trace;
+  list_item_t list[SET_SIZE];
+} set_t;
+
+set_t *setInit(void);
+int setAdd(set_t *set, ITEM_TYPE item);
+int setDel(set_t *set, ITEM_TYPE item);
+int setFirst(set_t *set, ITEM_TYPE *item);
+int setNext(set_t *set, ITEM_TYPE *item);
+int setDestroy(set_t *set);
+
+#endif
+
+/*
+ * GLX Hardware Device Driver common code
+ * Copyright (C) 1999 Keith Whitwell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef MM_INC
+#define MM_INC
+
+struct mem_block_t {
+  struct mem_block_t *next;
+  struct mem_block_t *heap;
+  int ofs,size;
+  int align;
+  int free:1;
+  int reserved:1;
+};
+typedef struct mem_block_t TMemBlock;
+typedef struct mem_block_t *PMemBlock;
+
+/* a heap is just the first block in a chain */
+typedef struct mem_block_t memHeap_t;
+
+static __inline__ int mmBlockSize(PMemBlock b)
+{ return b->size; }
+
+static __inline__ int mmOffset(PMemBlock b)
+{ return b->ofs; }
+
+static __inline__ void mmMarkReserved(PMemBlock b)
+{ b->reserved = 1; }
+
+/* 
+ * input: total size in bytes
+ * return: a heap pointer if OK, NULL if error
+ */
+memHeap_t *mmInit( int ofs, int size );
+
+
+
+memHeap_t *mmAddRange( memHeap_t *heap,
+		       int ofs,
+		       int size );
+
+
+/*
+ * Allocate 'size' bytes with 2^align2 bytes alignment,
+ * restrict the search to free memory after 'startSearch'
+ * depth and back buffers should be in different 4mb banks
+ * to get better page hits if possible
+ * input:	size = size of block
+ *       	align2 = 2^align2 bytes alignment
+ *		startSearch = linear offset from start of heap to begin search
+ * return: pointer to the allocated block, 0 if error
+ */
+PMemBlock  mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch );
+
+/*
+ * Free block starts at offset
+ * input: pointer to a block
+ * return: 0 if OK, -1 if error
+ */
+int  mmFreeMem( PMemBlock b );
+
+/*
+ * Reserve 'size' bytes block start at offset
+ * This is used to prevent allocation of memory already used
+ * by the X server for the front buffer, pixmaps, and cursor
+ * input: size, offset
+ * output: 0 if OK, -1 if error
+ */
+int mmReserveMem( memHeap_t *heap, int offset,int size );
+int mmFreeReserved( memHeap_t *heap, int offset );
+
+/*
+ * destroy MM
+ */
+void mmDestroy( memHeap_t *mmInit );
+
+/* For debuging purpose. */
+void mmDumpMemInfo( memHeap_t *mmInit );
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/drm/sis_mm.c linux/drivers/char/drm/sis_mm.c
--- linux-2.4.16/drivers/char/drm/sis_mm.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/char/drm/sis_mm.c	Fri Dec  7 19:34:54 2001
@@ -0,0 +1,307 @@
+/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
+ *
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Sung-Ching Lin <sclin@sis.com.tw>
+ * 
+ */
+
+#define __NO_VERSION__
+#include "sis.h"
+#include <linux/sisfb.h>
+#include "drmP.h"
+#include "sis_drm.h"
+#include "sis_drv.h"
+#include "sis_ds.h"
+
+#define MAX_CONTEXT 100
+#define VIDEO_TYPE 0 
+#define AGP_TYPE 1
+
+typedef struct {
+  int used;
+  int context;
+  set_t *sets[2]; /* 0 for video, 1 for AGP */
+} sis_context_t;
+
+static sis_context_t global_ppriv[MAX_CONTEXT];
+
+static int add_alloc_set(int context, int type, unsigned int val)
+{
+  int i, retval = 0;
+  
+  for(i = 0; i < MAX_CONTEXT; i++)
+    if(global_ppriv[i].used && global_ppriv[i].context == context){
+      retval = setAdd(global_ppriv[i].sets[type], val);
+      break;
+    }
+  return retval;
+}
+
+static int del_alloc_set(int context, int type, unsigned int val)
+{  
+  int i, retval = 0;
+  for(i = 0; i < MAX_CONTEXT; i++)
+    if(global_ppriv[i].used && global_ppriv[i].context == context){
+      retval = setDel(global_ppriv[i].sets[type], val);
+      break;
+    }
+  return retval;
+}
+
+/* fb management via fb device */ 
+#if 1
+int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  drm_sis_mem_t fb;
+  struct sis_memreq req;
+  int retval = 0;
+   
+  if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb)))
+	  return -EFAULT;
+  
+  req.size = fb.size;
+  sis_malloc(&req);
+  if(req.offset){
+    /* TODO */
+    fb.offset = req.offset;
+    fb.free = req.offset;
+    if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){
+      DRM_DEBUG("adding to allocation set fails\n");
+      sis_free(req.offset);
+      retval = -1;
+    }
+  }
+  else{  
+    fb.offset = 0;
+    fb.size = 0;
+    fb.free = 0;
+  }
+   
+  if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT;
+
+  DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
+
+  return retval;
+}
+
+int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  drm_sis_mem_t fb;
+  int retval = 0;
+    
+  if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb)))
+	  return -EFAULT;
+  
+  if(!fb.free){
+    return -1;
+  }
+
+  sis_free(fb.free);
+  if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
+    retval = -1;
+
+  DRM_DEBUG("free fb, offset = %d\n", fb.free);
+  
+  return retval;
+}
+
+#else
+
+int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  return -1;
+}
+
+int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  return 0;
+}
+
+#endif
+
+/* agp memory management */ 
+#if 1
+
+static memHeap_t *AgpHeap = NULL;
+
+int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  drm_sis_agp_t agp;
+   
+  if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp)))
+	  return -EFAULT;
+
+  AgpHeap = mmInit(agp.offset, agp.size);
+
+  DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+  
+  return 0;
+}
+
+int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  drm_sis_mem_t agp;
+  PMemBlock block;
+  int retval = 0;
+   
+  if(!AgpHeap)
+    return -1;
+  
+  if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp)))
+	  return -EFAULT;
+  
+  block = mmAllocMem(AgpHeap, agp.size, 0, 0);
+  if(block){
+    /* TODO */
+    agp.offset = block->ofs;
+    agp.free = (unsigned int)block;
+    if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){
+      DRM_DEBUG("adding to allocation set fails\n");
+      mmFreeMem((PMemBlock)agp.free);
+      retval = -1;
+    }
+  }
+  else{  
+    agp.offset = 0;
+    agp.size = 0;
+    agp.free = 0;
+  }
+   
+  if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT;
+
+  DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
+
+  return retval;
+}
+
+int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+  drm_sis_mem_t agp;
+  int retval = 0;
+
+  if(!AgpHeap)
+    return -1;
+    
+  if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp)))
+	  return -EFAULT;
+  
+  if(!agp.free){
+    return -1;
+  }
+
+  mmFreeMem((PMemBlock)agp.free);
+  if(!del_alloc_set(agp.context, AGP_TYPE, agp.free))
+    retval = -1;
+
+  DRM_DEBUG("free agp, free = %d\n", agp.free);
+  
+  return retval;
+}
+
+#endif
+
+int sis_init_context(int context)
+{
+	int i;
+	
+	for(i = 0; i < MAX_CONTEXT ; i++)
+	  if(global_ppriv[i].used && (global_ppriv[i].context == context))
+	    break;
+
+	if(i >= MAX_CONTEXT){
+	  for(i = 0; i < MAX_CONTEXT ; i++){
+	    if(!global_ppriv[i].used){
+	      global_ppriv[i].context = context;
+	      global_ppriv[i].used = 1;
+	      global_ppriv[i].sets[0] = setInit();
+	      global_ppriv[i].sets[1] = setInit();
+	      DRM_DEBUG("init allocation set, socket=%d, context = %d\n", 
+	                 i, context);
+	      break;
+	    }	
+	  }
+	  if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
+	     (global_ppriv[i].sets[1] == NULL)){
+	    return 0;
+	  }
+	}
+	
+	return 1;
+}
+
+int sis_final_context(int context)
+{
+	int i;
+
+	for(i=0; i<MAX_CONTEXT; i++)
+	  if(global_ppriv[i].used && (global_ppriv[i].context == context))
+	    break;
+          
+	if(i < MAX_CONTEXT){
+	  set_t *set;
+	  unsigned int item;
+	  int retval;
+	  
+  	  DRM_DEBUG("find socket %d, context = %d\n", i, context);
+
+	  /* Video Memory */
+	  set = global_ppriv[i].sets[0];
+	  retval = setFirst(set, &item);
+	  while(retval){
+   	    DRM_DEBUG("free video memory 0x%x\n", item);
+            sis_free(item);
+	    retval = setNext(set, &item);
+	  }
+	  setDestroy(set);
+
+	  /* AGP Memory */
+	  set = global_ppriv[i].sets[1];
+	  retval = setFirst(set, &item);
+	  while(retval){
+   	    DRM_DEBUG("free agp memory 0x%x\n", item);
+	    mmFreeMem((PMemBlock)item);
+	    retval = setNext(set, &item);
+	  }
+	  setDestroy(set);
+	  
+	  global_ppriv[i].used = 0;	  
+        }
+
+	/* turn-off auto-flip */
+	/* TODO */
+#if defined(SIS_STEREO)
+	flip_final();
+#endif
+	
+	return 1;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/i8k.c linux/drivers/char/i8k.c
--- linux-2.4.16/drivers/char/i8k.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/i8k.c	Tue Dec  4 19:25:30 2001
@@ -1,5 +1,7 @@
 /*
- * i8k.c -- Linux driver for accessing the SMM BIOS on Dell I8000 laptops
+ * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
+ *	    See http://www.debian.org/~dz/i8k/ for more information
+ *	    and for latest version of this driver.
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
@@ -19,15 +21,13 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
-#include <asm/io.h>
+#include <linux/apm_bios.h>
 #include <asm/uaccess.h>
+#include <asm/io.h>
 
 #include <linux/i8k.h>
 
-#define I8K_VERSION		"1.1 02/11/2001"
-#define I8K_BIOS_SIGNATURE	"Dell System Inspiron 8000"
-#define I8K_BIOS_SIGNATURE_ADDR 0x000ec000
-#define I8K_BIOS_VERSION_OFFSET	32
+#define I8K_VERSION		"1.7 21/11/2001"
 
 #define I8K_SMM_FN_STATUS	0x0025
 #define I8K_SMM_POWER_STATUS	0x0069
@@ -35,31 +35,47 @@
 #define I8K_SMM_GET_FAN		0x00a3
 #define I8K_SMM_GET_SPEED	0x02a3
 #define I8K_SMM_GET_TEMP	0x10a3
+#define I8K_SMM_GET_DELL_SIG	0xffa3
 #define I8K_SMM_BIOS_VERSION	0x00a6
 
 #define I8K_FAN_MULT		30
 #define I8K_MAX_TEMP		127
 
-#define I8K_FN_NONE		0x08
-#define I8K_FN_UP		0x09
-#define I8K_FN_DOWN		0x0a
-#define I8K_FN_MUTE		0x0c
+#define I8K_FN_NONE		0x00
+#define I8K_FN_UP		0x01
+#define I8K_FN_DOWN		0x02
+#define I8K_FN_MUTE		0x04
+#define I8K_FN_MASK		0x07
+#define I8K_FN_SHIFT		8
 
 #define I8K_POWER_AC		0x05
 #define I8K_POWER_BATTERY	0x01
 
 #define I8K_TEMPERATURE_BUG	1
 
-static char bios_version[4] = "?";
-static char bios_machine_id[16] = "?";
+#define DELL_SIGNATURE		"Dell Computer"
+
+static char *supported_models[] = {
+    "Inspiron",
+    "Latitude",
+    NULL
+};
+
+static char system_vendor[48] = "?";
+static char product_name [48] = "?";
+static char bios_version [4]  = "?";
+static char serial_number[16] = "?";
 
 int force = 0;
+int power_status = 0;
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
-MODULE_DESCRIPTION("Driver for accessing the SMM BIOS on Dell I8000 laptops");
+MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
 MODULE_LICENSE("GPL");
 MODULE_PARM(force, "i");
-MODULE_PARM_DESC(force, "Force loading without checking for an Inspiron 8000");
+MODULE_PARM(power_status, "i");
+MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
 static ssize_t i8k_read(struct file *, char *, size_t, loff_t *);
 static int i8k_ioctl(struct inode *, struct file *, unsigned int,
@@ -79,12 +95,19 @@
     unsigned int edi __attribute__ ((packed));
 } SMMRegisters;
 
+typedef struct {
+    u8	type;
+    u8	length;
+    u16	handle;
+} DMIHeader;
+
 /*
- * Call the System Management Mode BIOS.
+ * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
  */
 static int i8k_smm(SMMRegisters *regs)
 {
     int rc;
+    int eax = regs->eax;
 
     asm("pushl %%eax\n\t" \
 	"movl 0(%%eax),%%edx\n\t" \
@@ -112,7 +135,7 @@
 	: "a" (regs)
 	: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
 
-    if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff)) {
+    if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
 	return -EINVAL;
     }
 
@@ -137,11 +160,12 @@
 }
 
 /*
- * Read the machine id. Not yet implemented.
+ * Read the machine id.
  */
-static int i8k_get_machine_id(unsigned char *buff)
+static int i8k_get_serial_number(unsigned char *buff)
 {
-    return -EINVAL;
+    strncpy(buff, serial_number, 16);
+    return 0;
 }
 
 /*
@@ -157,7 +181,7 @@
 	return rc;
     }
 
-    switch ((regs.eax & 0xff00) >> 8) {
+    switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
     case I8K_FN_UP:
 	return I8K_VOL_UP;
     case I8K_FN_DOWN:
@@ -281,6 +305,23 @@
     return temp;
 }
 
+static int i8k_get_dell_signature(void)
+{
+    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+    int rc;
+
+    regs.eax = I8K_SMM_GET_DELL_SIG;
+    if ((rc=i8k_smm(&regs)) < 0) {
+	return rc;
+    }
+
+    if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
+	return 0;
+    } else {
+	return -1;
+    }
+}
+
 static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
 		     unsigned long arg)
 {
@@ -299,7 +340,7 @@
 
     case I8K_MACHINE_ID:
 	memset(buff, 0, 16);
-	val = i8k_get_machine_id(buff);
+	val = i8k_get_serial_number(buff);
 	break;
 
     case I8K_FN_STATUS:
@@ -375,13 +416,17 @@
     int n, fn_key, cpu_temp, ac_power;
     int left_fan, right_fan, left_speed, right_speed;
 
-    cpu_temp    = i8k_get_cpu_temp();
-    left_fan    = i8k_get_fan_status(I8K_FAN_LEFT);
-    right_fan   = i8k_get_fan_status(I8K_FAN_RIGHT);
-    left_speed  = i8k_get_fan_speed(I8K_FAN_LEFT);
-    right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT);
-    ac_power    = i8k_get_power_status();
-    fn_key      = i8k_get_fn_status();
+    cpu_temp     = i8k_get_cpu_temp();			/* 11100 µs */
+    left_fan     = i8k_get_fan_status(I8K_FAN_LEFT);	/*   580 µs */
+    right_fan    = i8k_get_fan_status(I8K_FAN_RIGHT);	/*   580 µs */
+    left_speed   = i8k_get_fan_speed(I8K_FAN_LEFT);	/*   580 µs */
+    right_speed  = i8k_get_fan_speed(I8K_FAN_RIGHT);	/*   580 µs */
+    fn_key       = i8k_get_fn_status();			/*   750 µs */
+    if (power_status) {
+	ac_power = i8k_get_power_status();		/* 14700 µs */
+    } else {
+	ac_power = -1;
+    }
 
     /*
      * Info:
@@ -400,7 +445,7 @@
     n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
 		I8K_PROC_FMT,
 		bios_version,
-		bios_machine_id,
+		serial_number,
 		cpu_temp,
 		left_fan,
 		right_fan,
@@ -438,76 +483,253 @@
     return len;
 }
 
+static char* __init string_trim(char *s, int size)
+{
+    int len;
+    char *p;
+
+    if ((len = strlen(s)) > size) {
+	len = size;
+    }
+
+    for (p=s+len-1; len && (*p==' '); len--,p--) {
+	*p = '\0';
+    }
+
+    return s;
+}
+
+/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
+
 /*
- * Probe for the presence of an Inspiron I8000.
+ * |<-- dmi->length -->|
+ * |                   |
+ * |dmi header    s=N  | string1,\0, ..., stringN,\0, ..., \0
+ *                |                       |
+ *                +-----------------------+
  */
-static int i8k_probe(void)
+static char* __init dmi_string(DMIHeader *dmi, u8 s)
 {
-    unsigned char *buff, *p;
-    unsigned char bios_vers[4];
-    int version;
+    u8 *p;
+
+    if (!s) {
+	return "";
+    }
+    s--;
+
+    p = (u8 *)dmi + dmi->length;
+    while (s > 0) {
+	p += strlen(p);
+	p++;
+	s--;
+    }
+
+    return p;
+}
+
+static void __init dmi_decode(DMIHeader *dmi)
+{
+    u8 *data = (u8 *) dmi;
+    char *p;
+
+#ifdef I8K_DEBUG
+    int i;
+    printk("%08x ", (int)data);
+    for (i=0; i<data[1] && i<64; i++) {
+	printk("%02x ", data[i]);
+    }
+    printk("\n");
+#endif
+
+    switch (dmi->type) {
+    case  0:	/* BIOS Information */
+	p = dmi_string(dmi,data[5]);
+	if (*p) {
+	    strncpy(bios_version, p, sizeof(bios_version));
+	    string_trim(bios_version, sizeof(bios_version));
+	}
+	break;	
+    case 1:	/* System Information */
+	p = dmi_string(dmi,data[4]);
+	if (*p) {
+	    strncpy(system_vendor, p, sizeof(system_vendor));
+	    string_trim(system_vendor, sizeof(system_vendor));
+	}
+	p = dmi_string(dmi,data[5]);
+	if (*p) {
+	    strncpy(product_name, p, sizeof(product_name));
+	    string_trim(product_name, sizeof(product_name));
+	}
+	p = dmi_string(dmi,data[7]);
+	if (*p) {
+	    strncpy(serial_number, p, sizeof(serial_number));
+	    string_trim(serial_number, sizeof(serial_number));
+	}
+	break;
+    }
+}
+
+static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
+{
+    u8 *buf;
+    u8 *data;
+    DMIHeader *dmi;
+    int i = 1;
+
+    buf = ioremap(base, len);
+    if (buf == NULL) {
+	return -1;
+    }
+    data = buf;
 
     /*
-     * Until Dell tell us how to reliably check for an Inspiron system
-     * look for a signature at a fixed location in the BIOS memory.
-     * Ugly but safe.
+     * Stop when we see al the items the table claimed to have
+     * or we run off the end of the table (also happens)
      */
-    if (!force) {
-	buff = ioremap(I8K_BIOS_SIGNATURE_ADDR, I8K_BIOS_VERSION_OFFSET+4);
-	if (buff == NULL) {
-	    printk("i8k: ioremap failed\n");
-	    return -ENODEV;
+    while ((i<num) && ((data-buf) < len)) {
+	dmi = (DMIHeader *)data;
+	/*
+	 * Avoid misparsing crud if the length of the last
+	 * record is crap
+	 */
+	if ((data-buf+dmi->length) >= len) {
+	    break;
+	}
+	fn(dmi);
+	data += dmi->length;
+	/*
+	 * Don't go off the end of the data if there is
+	 * stuff looking like string fill past the end
+	 */
+	while (((data-buf) < len) && (*data || data[1])) {
+	    data++;
 	}
-	if (strncmp(buff,I8K_BIOS_SIGNATURE,sizeof(I8K_BIOS_SIGNATURE)) != 0) {
-	    printk("i8k: Inspiron 8000 BIOS signature not found\n");
-	    iounmap(buff);
-	    return -ENODEV;
+	data += 2;
+	i++;
+    }
+    iounmap(buf);
+
+    return 0;
+}
+
+static int __init dmi_iterate(void (*decode)(DMIHeader *))
+{
+    unsigned char buf[20];
+    long fp = 0x000e0000L;
+    fp -= 16;
+
+    while (fp < 0x000fffffL) {
+	fp += 16;
+	isa_memcpy_fromio(buf, fp, 20);
+	if (memcmp(buf, "_DMI_", 5)==0) {
+	    u16 num  = buf[13]<<8  | buf[12];
+	    u16 len  = buf [7]<<8  | buf [6];
+	    u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
+#ifdef I8K_DEBUG
+	    printk(KERN_INFO "DMI %d.%d present.\n",
+		   buf[14]>>4, buf[14]&0x0F);
+	    printk(KERN_INFO "%d structures occupying %d bytes.\n",
+		   buf[13]<<8 | buf[12],
+		   buf [7]<<8 | buf[6]);
+	    printk(KERN_INFO "DMI table at 0x%08X.\n",
+		   buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
+#endif
+	    if (dmi_table(base, len, num, decode)==0) {
+		return 0;
+	    }
 	}
-	strncpy(bios_vers, buff+I8K_BIOS_VERSION_OFFSET, 3);
-	bios_vers[3] = '\0';
-	iounmap(buff);
-    }
-    if (force >= 2) {
-	buff = ioremap(0x000c0000, 0x00100000-0x000c0000);
-	if (buff == NULL) {
-	    printk("i8k: ioremap failed\n");
+    }
+    return -1;
+}
+/* end of DMI code */
+
+/*
+ * Get DMI information.
+ */
+static int __init i8k_dmi_probe(void)
+{
+    char **p;
+
+    if (dmi_iterate(dmi_decode) != 0) {
+	printk(KERN_INFO "i8k: unable to get DMI information\n");
+	return -ENODEV;
+    }
+
+    if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
+	printk(KERN_INFO "i8k: not running on a Dell system\n");
+	return -ENODEV;
+    }
+
+    for (p=supported_models; ; p++) {
+	if (!*p) {
+	    printk(KERN_INFO "i8k: unsupported model: %s\n", product_name);
 	    return -ENODEV;
 	}
-	for (p=buff; (p-buff)<(0x00100000-0x000c0000); p+=16) {
-	    if (strncmp(p,I8K_BIOS_SIGNATURE,sizeof(I8K_BIOS_SIGNATURE))==0) {
-		printk("i8k: Inspiron 8000 BIOS signature found at %08x\n",
-		       0x000c0000+(p-buff));
-		break;
-	    }
+	if (strncmp(product_name,*p,strlen(*p)) == 0) {
+	    break;
 	}
-	iounmap(buff);
     }
 
+    return 0;
+}
+
+/*
+ * Probe for the presence of a supported laptop.
+ */
+static int __init i8k_probe(void)
+{
+    char buff[4];
+    int version;
+    int smm_found = 0;
+
     /*
-     * Next try to get the BIOS version with an SMM call. If this
-     * fails SMM can't be reliably used on this system.
+     * Get DMI information
      */
-    version = i8k_get_bios_version();
-    if (version <= 0) {
-	printk("i8k: unable to get BIOS version\n");
-	return -ENODEV;
+    if (i8k_dmi_probe() != 0) {
+	printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
+	       system_vendor, product_name, bios_version);
     }
-    bios_version[0] = (version >> 16) & 0xff;
-    bios_version[1] = (version >>  8) & 0xff;
-    bios_version[2] = (version)       & 0xff;
-    bios_version[3] = '\0';
 
     /*
-     * Finally check if the two versions match.
+     * Get SMM Dell signature
      */
-    if (!force) {
-	if (strncmp(bios_version,bios_vers,sizeof(bios_version)) != 0) {
-	    printk("i8k: BIOS version mismatch: %s != %s\n",
-		   bios_version, bios_vers);
-	    return -ENODEV;
+    if (i8k_get_dell_signature() != 0) {
+	printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
+    } else {
+	smm_found = 1;
+    }
+
+    /*
+     * Get SMM BIOS version.
+     */
+    version = i8k_get_bios_version();
+    if (version <= 0) {
+	printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
+    } else {
+	smm_found = 1;
+	buff[0] = (version >> 16) & 0xff;
+	buff[1] = (version >>  8) & 0xff;
+	buff[2] = (version)       & 0xff;
+	buff[3] = '\0';
+	/*
+	 * If DMI BIOS version is unknown use SMM BIOS version.
+	 */
+	if (bios_version[0] == '?') {
+	    strcpy(bios_version, buff);
+	}
+	/*
+	 * Check if the two versions match.
+	 */
+	if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
+	    printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n",
+		   buff, bios_version);
 	}
     }
 
+    if (!smm_found && !force) {
+	return -ENODEV;
+    }
+
     return 0;
 }
 
@@ -518,7 +740,7 @@
 {
     struct proc_dir_entry *proc_i8k;
 
-    /* Are we running on an Inspiron 8000 laptop? */
+    /* Are we running on an supported laptop? */
     if (i8k_probe() != 0) {
 	return -ENODEV;
     }
@@ -532,7 +754,7 @@
     SET_MODULE_OWNER(proc_i8k);
 
     printk(KERN_INFO
-	   "Inspiron 8000 SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
+	   "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
 	   I8K_VERSION);
 
     return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c
--- linux-2.4.16/drivers/char/ip2/i2cmd.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/ip2/i2cmd.c	Tue Dec  4 19:25:30 2001
@@ -139,7 +139,7 @@
 //static UCHAR ct86[]={ 2, BTH,     0x56,0                   }; // RCV_ENABLE
 static UCHAR ct87[] = { 1, BYP,     0x57                     }; // HW_TEST
 //static UCHAR ct88[]={ 3, BTH,     0x58,0,0                 }; // RCV_THRESHOLD
-static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
+//static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
 //static UCHAR ct90[]={ 3, BYP,     0x5A,0,0                 }; // Set SILO
 //static UCHAR ct91[]={ 2, BYP,     0x5B,0                   }; // timed break
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/ip2.c linux/drivers/char/ip2.c
--- linux-2.4.16/drivers/char/ip2.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/ip2.c	Tue Dec  4 19:25:30 2001
@@ -33,9 +33,10 @@
 */
 static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
 static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; 
-static int poll_only = 0;
 
 #ifdef MODULE
+
+static int poll_only = 0;
 
 #	if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 		MODULE_AUTHOR("Doug McNash");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/joystick/cs461x.c linux/drivers/char/joystick/cs461x.c
--- linux-2.4.16/drivers/char/joystick/cs461x.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/joystick/cs461x.c	Fri Dec  7 18:08:43 2001
@@ -313,7 +313,7 @@
         name:           "PCI Gameport",
         id_table:       cs461x_pci_tbl,
         probe:          cs461x_pci_probe,
-        remove:         cs461x_pci_remove,
+        remove:         __devexit_p(cs461x_pci_remove),
 };
 
 int __init js_cs461x_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/joystick/emu10k1-gp.c linux/drivers/char/joystick/emu10k1-gp.c
--- linux-2.4.16/drivers/char/joystick/emu10k1-gp.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/joystick/emu10k1-gp.c	Fri Dec  7 18:08:43 2001
@@ -108,7 +108,7 @@
         name:           "Emu10k1 Gameport",
         id_table:       emu_tbl,
         probe:          emu_probe,
-        remove:         emu_remove,
+        remove:         __devexit_p(emu_remove),
 };
 
 int __init emu_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/joystick/pcigame.c linux/drivers/char/joystick/pcigame.c
--- linux-2.4.16/drivers/char/joystick/pcigame.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/joystick/pcigame.c	Fri Dec  7 18:08:43 2001
@@ -180,7 +180,7 @@
 	name:		"pcigame",
 	id_table:	pcigame_id_table,
 	probe:		pcigame_probe,
-	remove:		pcigame_remove,
+	remove:		__devexit_p(pcigame_remove),
 };
 
 int __init pcigame_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/mem.c linux/drivers/char/mem.c
--- linux-2.4.16/drivers/char/mem.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/mem.c	Thu Dec  6 20:33:49 2001
@@ -272,6 +272,8 @@
  	return virtr + read;
 }
 
+extern long vwrite(char *buf, char *addr, unsigned long count);
+
 /*
  * This function writes to the *virtual* memory as seen by the kernel.
  */
@@ -279,12 +281,46 @@
 			  size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
+	ssize_t wrote = 0;
+	ssize_t virtr = 0;
+	char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
+
+	if (p < (unsigned long) high_memory) {
+		wrote = count;
+		if (count > (unsigned long) high_memory - p)
+			wrote = (unsigned long) high_memory - p;
+
+		wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos);
+
+		p += wrote;
+		buf += wrote;
+		count -= wrote;
+	}
+
+	if (count > 0) {
+		kbuf = (char *)__get_free_page(GFP_KERNEL);
+		if (!kbuf)
+			return -ENOMEM;
+		while (count > 0) {
+			int len = count;
+
+			if (len > PAGE_SIZE)
+				len = PAGE_SIZE;
+			if (len && copy_from_user(kbuf, buf, len)) {
+				free_page((unsigned long)kbuf);
+				return -EFAULT;
+			}
+			len = vwrite(kbuf, (char *)p, len);
+			count -= len;
+			buf += len;
+			virtr += len;
+			p += len;
+		}
+		free_page((unsigned long)kbuf);
+	}
 
-	if (p >= (unsigned long) high_memory)
-		return 0;
-	if (count > (unsigned long) high_memory - p)
-		count = (unsigned long) high_memory - p;
-	return do_write_mem(file, (void*)p, p, buf, count, ppos);
+ 	*ppos = p;
+ 	return virtr + wrote;
 }
 
 #if !defined(__mc68000__)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/pcmcia/serial_cs.c linux/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.16/drivers/char/pcmcia/serial_cs.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/pcmcia/serial_cs.c	Tue Dec  4 19:25:30 2001
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.123 2000/08/24 18:46:38
+    serial_cs.c 1.128 2001/10/18 12:18:35
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     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
+    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
@@ -44,6 +44,7 @@
 #include <linux/major.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -53,30 +54,32 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA serial card driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
 
 /* Enable the speaker? */
-static int do_sound = 1;
+INT_MODULE_PARM(do_sound, 1);
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(do_sound, "i");
+#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)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -93,6 +96,8 @@
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
     { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
     { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
     { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
@@ -357,7 +362,6 @@
 
 found_port:
     if (i != CS_SUCCESS) {
-	printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n");
 	cs_error(link->handle, RequestIO, i);
 	return -1;
     }
@@ -437,7 +441,6 @@
     
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
-	printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n");
 	cs_error(link->handle, RequestIRQ, i);
 	link->irq.AssignedIRQ = 0;
     }
@@ -663,5 +666,3 @@
 
 module_init(init_serial_cs);
 module_exit(exit_serial_cs);
-
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/pty.c linux/drivers/char/pty.c
--- linux-2.4.16/drivers/char/pty.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/pty.c	Tue Dec  4 19:25:30 2001
@@ -334,8 +334,7 @@
 	/*  Register a slave for the master  */
 	if (tty->driver.major == PTY_MASTER_MAJOR)
 		tty_register_devfs(&tty->link->driver,
-				   DEVFS_FL_CURRENT_OWNER |
-				   DEVFS_FL_NO_PERSISTENCE | DEVFS_FL_WAIT,
+				   DEVFS_FL_CURRENT_OWNER | DEVFS_FL_WAIT,
 				   tty->link->driver.minor_start +
 				   MINOR(tty->device)-tty->driver.minor_start);
 	retval = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/rtc.c linux/drivers/char/rtc.c
--- linux-2.4.16/drivers/char/rtc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/rtc.c	Tue Dec  4 19:25:30 2001
@@ -785,6 +785,9 @@
 		printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
 #endif
 #if RTC_IRQ
+	if (rtc_has_irq == 0)
+		goto no_irq2;
+
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	spin_lock_irq(&rtc_lock);
@@ -792,6 +795,7 @@
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
 	spin_unlock_irq(&rtc_lock);
 	rtc_freq = 1024;
+no_irq2:
 #endif
 
 	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.4.16/drivers/char/serial.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/serial.c	Fri Dec  7 18:08:43 2001
@@ -3133,6 +3133,10 @@
  * 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.
+ *
+ * Note that on failure, we don't decrement the module use count - the tty
+ * later will call rs_close, which will decrement it for us as long as
+ * tty->driver_data is set non-NULL. --rmk
  */
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
@@ -3153,10 +3157,8 @@
 	}
 	tty->driver_data = info;
 	info->tty = tty;
-	if (serial_paranoia_check(info, tty->device, "rs_open")) {
-		MOD_DEC_USE_COUNT;		
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
-	}
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
@@ -3171,10 +3173,8 @@
 	 */
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			MOD_DEC_USE_COUNT;
+		if (!page)
 			return -ENOMEM;
-		}
 		if (tmp_buf)
 			free_page(page);
 		else
@@ -3188,7 +3188,6 @@
 	    (info->flags & ASYNC_CLOSING)) {
 		if (info->flags & ASYNC_CLOSING)
 			interruptible_sleep_on(&info->close_wait);
-		MOD_DEC_USE_COUNT;
 #ifdef SERIAL_DO_RESTART
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
@@ -3201,10 +3200,8 @@
 	 * Start up serial port
 	 */
 	retval = startup(info);
-	if (retval) {
-		MOD_DEC_USE_COUNT;
+	if (retval)
 		return retval;
-	}
 
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
@@ -3212,7 +3209,6 @@
 		printk("rs_open returning after block_til_ready with %d\n",
 		       retval);
 #endif
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
@@ -4896,7 +4892,7 @@
 static struct pci_driver serial_pci_driver = {
        name:           "serial",
        probe:          serial_init_one,
-       remove:	       serial_remove_one,
+       remove:	       __devexit_p(serial_remove_one),
        id_table:       serial_pci_tbl,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/sonypi.c linux/drivers/char/sonypi.c
--- linux-2.4.16/drivers/char/sonypi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/sonypi.c	Fri Dec  7 19:17:35 2001
@@ -617,8 +617,11 @@
 		goto out3;
 	}
 
+#if !defined(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();
@@ -666,6 +669,11 @@
 		sonypi_type2_dis();
 	else
 		sonypi_type1_dis();
+#if !defined(CONFIG_ACPI)
+	/* disable ACPI mode */
+	if (fnkeyinit)
+		outb(0xf1, 0xb2);
+#endif
 	free_irq(sonypi_device.irq, sonypi_irq);
 	release_region(sonypi_device.ioport1, sonypi_device.region_size);
 	misc_deregister(&sonypi_misc_device);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/sonypi.h linux/drivers/char/sonypi.h
--- linux-2.4.16/drivers/char/sonypi.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/sonypi.h	Fri Dec  7 19:17:35 2001
@@ -35,7 +35,7 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	1
-#define SONYPI_DRIVER_MINORVERSION	7
+#define SONYPI_DRIVER_MINORVERSION	8
 
 #include <linux/types.h>
 #include <linux/pci.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.4.16/drivers/char/tty_io.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/char/tty_io.c	Tue Dec  4 19:25:30 2001
@@ -1343,7 +1343,7 @@
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		minor -= driver->minor_start;
 		devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
-		tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE,
+		tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
 				   pts_driver[major].minor_start + minor);
 		noctty = 1;
 		goto init_dev_done;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.4.16/drivers/ide/ide-disk.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/ide/ide-disk.c	Thu Dec  6 14:48:42 2001
@@ -858,8 +858,10 @@
 		}
 		/* We must remove proc entries defined in this module.
 		   Otherwise we oops while accessing these entries */
+#ifdef CONFIG_PROC_FS
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
+#endif
 	}
 	ide_unregister_module(&idedisk_module);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- linux-2.4.16/drivers/ide/ide-floppy.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/ide/ide-floppy.c	Thu Dec  6 14:48:42 2001
@@ -2071,8 +2071,10 @@
 		}
 		/* We must remove proc entries defined in this module.
 		   Otherwise we oops while accessing these entries */
+#ifdef CONFIG_PROC_FS
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idefloppy_proc);
+#endif
 	}
 	ide_unregister_module(&idefloppy_module);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- linux-2.4.16/drivers/ide/ide-tape.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/ide/ide-tape.c	Wed Dec  5 16:58:08 2001
@@ -6182,6 +6182,7 @@
 };
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
 
 static void __exit idetape_exit (void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c
--- linux-2.4.16/drivers/ieee1394/hosts.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/hosts.c	Tue Dec  4 19:25:30 2001
@@ -170,10 +170,10 @@
 	list_for_each(hlh, &tmpl->hosts) {
 		host = list_entry(hlh, struct hpsb_host, list);
                 if (host->initialized) {
+                        highlevel_remove_host(host);
+
                         host->initialized = 0;
                         abort_requests(host);
-
-                        highlevel_remove_host(host);
 
                         tmpl->release_host(host);
                         while (test_bit(0, &host->timeout_tq.sync)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.16/drivers/ieee1394/ieee1394_core.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Tue Dec  4 19:25:30 2001
@@ -318,7 +318,7 @@
 
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 {
-        host->node_id = 0xffc0 | phyid;
+        host->node_id = LOCAL_BUS | phyid;
         host->in_bus_reset = 0;
         host->is_root = isroot;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- linux-2.4.16/drivers/ieee1394/ieee1394_syms.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/ieee1394_syms.c	Thu Jan  1 00:00:00 1970
@@ -1,88 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Exported symbols for module usage.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_hotplug.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-
-EXPORT_SYMBOL(hpsb_register_lowlevel);
-EXPORT_SYMBOL(hpsb_unregister_lowlevel);
-EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_inc_host_usage);
-EXPORT_SYMBOL(hpsb_dec_host_usage);
-
-EXPORT_SYMBOL(alloc_hpsb_packet);
-EXPORT_SYMBOL(free_hpsb_packet);
-EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_reset_bus);
-EXPORT_SYMBOL(hpsb_bus_reset);
-EXPORT_SYMBOL(hpsb_selfid_received);
-EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_packet_sent);
-EXPORT_SYMBOL(hpsb_packet_received);
-
-EXPORT_SYMBOL(get_tlabel);
-EXPORT_SYMBOL(free_tlabel);
-EXPORT_SYMBOL(fill_async_readquad);
-EXPORT_SYMBOL(fill_async_readquad_resp);
-EXPORT_SYMBOL(fill_async_readblock);
-EXPORT_SYMBOL(fill_async_readblock_resp);
-EXPORT_SYMBOL(fill_async_writequad);
-EXPORT_SYMBOL(fill_async_writeblock);
-EXPORT_SYMBOL(fill_async_write_resp);
-EXPORT_SYMBOL(fill_async_lock);
-EXPORT_SYMBOL(fill_async_lock_resp);
-EXPORT_SYMBOL(fill_iso_packet);
-EXPORT_SYMBOL(fill_phy_packet);
-EXPORT_SYMBOL(hpsb_make_readqpacket);
-EXPORT_SYMBOL(hpsb_make_readbpacket);
-EXPORT_SYMBOL(hpsb_make_writeqpacket);
-EXPORT_SYMBOL(hpsb_make_writebpacket);
-EXPORT_SYMBOL(hpsb_make_lockpacket);
-EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_packet_success);
-EXPORT_SYMBOL(hpsb_make_packet);
-EXPORT_SYMBOL(hpsb_read);
-EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-
-EXPORT_SYMBOL(hpsb_register_highlevel);
-EXPORT_SYMBOL(hpsb_unregister_highlevel);
-EXPORT_SYMBOL(hpsb_register_addrspace);
-EXPORT_SYMBOL(hpsb_listen_channel);
-EXPORT_SYMBOL(hpsb_unlisten_channel);
-EXPORT_SYMBOL(highlevel_read);
-EXPORT_SYMBOL(highlevel_write);
-EXPORT_SYMBOL(highlevel_lock);
-EXPORT_SYMBOL(highlevel_lock64);
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-EXPORT_SYMBOL(highlevel_host_reset);
-EXPORT_SYMBOL(highlevel_add_one_host);
-
-EXPORT_SYMBOL(hpsb_guid_get_entry);
-EXPORT_SYMBOL(hpsb_nodeid_get_entry);
-EXPORT_SYMBOL(hpsb_get_host_by_ne);
-EXPORT_SYMBOL(hpsb_guid_fill_packet);
-EXPORT_SYMBOL(hpsb_register_protocol);
-EXPORT_SYMBOL(hpsb_unregister_protocol);
-EXPORT_SYMBOL(hpsb_release_unit_directory);
-
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- linux-2.4.16/drivers/ieee1394/nodemgr.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/nodemgr.c	Tue Dec  4 19:25:30 2001
@@ -359,7 +359,7 @@
 	kfree(buf);
 	kfree(envp);
 	if (value != 0)
-		HPSB_DEBUG("NodeMgr: hotplug policy returned 0x%x", value);
+		HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value);
 }
 
 #else
@@ -369,9 +369,8 @@
 {
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");
-#else
-	return;
 #endif
+	return;
 } 
 
 #endif /* CONFIG_HOTPLUG */
@@ -582,13 +581,13 @@
                                struct hpsb_host *host, nodeid_t nodeid)
 {
 	struct list_head *lh;
+	struct unit_directory *ud;
 
-	if (ne->nodeid != nodeid)
+	if (ne->nodeid != nodeid) {
 		HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT,
 			   NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid));
-
-	ne->host = host;
-	ne->nodeid = nodeid;
+		ne->nodeid = nodeid;
+	}
 
 	if (ne->busopt.generation != ((busoptions >> 4) & 0xf))
 		nodemgr_process_config_rom (ne, busoptions);
@@ -597,8 +596,6 @@
 	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
 
 	list_for_each (lh, &ne->unit_directories) {
-		struct unit_directory *ud;
-
 		ud = list_entry (lh, struct unit_directory, node_list);
 		if (ud->driver != NULL && ud->driver->update != NULL)
 			ud->driver->update(ud);
@@ -679,57 +676,76 @@
 	return;
 }
 
+/* Used to schedule each nodes config rom probe */
+struct node_probe_task {
+	nodeid_t nodeid;
+	struct hpsb_host *host;
+	atomic_t *count;
+	struct tq_struct task;
+};
+
 /* This is where we probe the nodes for their information and provided
  * features.  */
-static void nodemgr_node_probe(void *data)
+static void nodemgr_node_probe_one(void *__npt)
 {
-	struct hpsb_host *host = (struct hpsb_host *)data;
-        struct selfid *sid = (struct selfid *)host->topology_map;
-	struct list_head *lh, *next;
+	struct node_probe_task *npt = (struct node_probe_task *)__npt;
 	struct node_entry *ne;
-        int nodecount = host->node_count;
-        nodeid_t nodeid = LOCAL_BUS;
 	quadlet_t buffer[5];
 	octlet_t guid;
-	unsigned long flags;
 
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
-        for (; nodecount; nodecount--, nodeid++, sid++) {
-		/* Skip extended, and non-active node's */
-                while (sid->extended)
-			sid++;
-                if (!sid->link_active)
-			continue;
 
-		if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2))
-			continue;
+	if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2))
+		goto probe_complete;
 
-		if (buffer[1] != IEEE1394_BUSID_MAGIC) {
-			/* This isn't a 1394 device */
-			HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
-				 NODE_BUS_ARGS(nodeid));
-			continue;
-		}
+	if (buffer[1] != IEEE1394_BUSID_MAGIC) {
+		/* This isn't a 1394 device */
+		HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
+			 NODE_BUS_ARGS(npt->nodeid));
+		goto probe_complete;
+	}
+
+	guid = ((u64)buffer[3] << 32) | buffer[4];
+	ne = hpsb_guid_get_entry(guid);
+
+	if (!ne)
+		nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid);
+	else
+		nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid);
+
+probe_complete:
+	atomic_dec(npt->count);
+
+	kfree(npt);
+
+	return;
+}
 
-		guid = ((u64)buffer[3] << 32) | buffer[4];
-		ne = hpsb_guid_get_entry(guid);
+static void nodemgr_node_probe_cleanup(void *__npt)
+{
+	struct node_probe_task *npt = (struct node_probe_task *)__npt;
+	unsigned long flags;
+	struct list_head *lh, *next;
+	struct node_entry *ne;
+
+	/* If things aren't done yet, reschedule ourselves. */
+        if (atomic_read(npt->count)) {
+                schedule_task(&npt->task);
+		return;
+	}
 
-		if (!ne)
-			nodemgr_create_node(guid, buffer[2], host, nodeid);
-		else
-			nodemgr_update_node(ne, buffer[2], host, nodeid);
-        }
+	kfree(npt->count);
 
 	/* Now check to see if we have any nodes that aren't referenced
 	 * any longer.  */
-        write_lock_irqsave(&node_lock, flags);
+	write_lock_irqsave(&node_lock, flags);
 	for (lh = node_list.next; lh != &node_list; lh = next) {
 		ne = list_entry(lh, struct node_entry, list);
 		next = lh->next;
 
 		/* Only checking this host */
-		if (ne->host != host)
+		if (ne->host != npt->host)
 			continue;
 
 		/* If the generation didn't get updated, then either the
@@ -741,9 +757,70 @@
 	}
 	write_unlock_irqrestore(&node_lock, flags);
 
+	kfree(npt);
+
 	return;
 }
 
+static void nodemgr_node_probe(void *__host)
+{
+	struct hpsb_host *host = (struct hpsb_host *)__host;
+	int nodecount = host->node_count;
+	struct selfid *sid = (struct selfid *)host->topology_map;
+	nodeid_t nodeid = LOCAL_BUS;
+	struct node_probe_task *npt;
+	atomic_t *count;
+
+	count = kmalloc(sizeof (*count), GFP_KERNEL);
+
+	if (count == NULL) {
+		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+		return;
+	}
+
+	atomic_set(count, 0);
+
+	for (; nodecount; nodecount--, nodeid++, sid++) {
+		while (sid->extended)
+			sid++;
+		if (!sid->link_active || nodeid == host->node_id)
+			continue;
+
+		npt = kmalloc(sizeof (*npt), GFP_KERNEL);
+
+		if (npt == NULL) {
+			HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+			break;
+		}
+
+		INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt);
+		npt->host = host;
+		npt->nodeid = nodeid;
+		npt->count = count;
+
+		atomic_inc(count);
+
+		schedule_task(&npt->task);
+	}
+
+	/* Now schedule a task to clean things up after the node probes
+	 * are done.  */
+	npt = kmalloc (sizeof (*npt), GFP_KERNEL);
+
+	if (npt == NULL) {
+		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+		return;
+	}
+
+	INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt);
+	npt->host = host;
+	npt->nodeid = 0;
+	npt->count = count;
+
+	schedule_task(&npt->task);
+
+	return;
+}
 
 struct node_entry *hpsb_guid_get_entry(u64 guid)
 {
@@ -864,7 +941,7 @@
 	write_unlock_irqrestore(&node_lock, flags);
 
 	spin_lock_irqsave (&host_info_lock, flags);
-	list_for_each(lh, &host_info_list) {
+	list_for_each_safe(lh, next, &host_info_list) {
 		struct host_info *hi = list_entry(lh, struct host_info, list);
 		if (hi->host == host) {
 			list_del(&hi->list);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- linux-2.4.16/drivers/ieee1394/ohci1394.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/ohci1394.c	Fri Dec  7 18:08:43 2001
@@ -106,16 +106,12 @@
 #include <linux/init.h>
 
 #ifdef CONFIG_ALL_PPC
-#include <asm/feature.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #endif
 
-/* Revert to old bus reset algorithm that works on my Pismo until
- * the new one is fixed
- */
-#undef BUSRESET_WORKAROUND
-
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
@@ -175,7 +171,7 @@
 MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
 
 static char version[] __devinitdata =
-	"v0.51 08/08/01 Ben Collins <bcollins@debian.org>";
+	"$Revision: 1.80 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -516,12 +512,9 @@
 	/* After enabling LPS, we need to wait for the connection
 	 * between phy and link to be established.  This should be
 	 * signaled by the LPS bit becoming 1, but this happens
-	 * immediately.  Instead we wait for reads from LinkControl to
-	 * give a valid result, i.e. not 0xffffffff. */
-	while (reg_read(ohci, OHCI1394_LinkControlSet) == 0xffffffff) {
-		DBGMSG(ohci->id, "waiting for phy-link connection");
-		mdelay(2);
-	}
+	 * immediately.  There seems to be no consistent way to wait
+	 * for this, but 50ms seems to be enough. */
+	mdelay(50);
 
 	/* Set the bus number */
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
@@ -1131,11 +1124,7 @@
 	 * selfIDComplete interrupt. */
 	spin_lock_irqsave(&ohci->event_lock, flags);
 	event = reg_read(ohci, OHCI1394_IntEventClear);
-#ifdef BUSRESET_WORKAROUND
-	reg_write(ohci, OHCI1394_IntEventClear, event);
-#else
 	reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
-#endif
 	spin_unlock_irqrestore(&ohci->event_lock, flags);
 
 	if (!event) return;
@@ -1154,11 +1143,17 @@
 		 * selfID phase, so we disable busReset interrupts, to
 		 * avoid burying the cpu in interrupt requests. */
 		spin_lock_irqsave(&ohci->event_lock, flags);
-#ifdef BUSRESET_WORKAROUND
-		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-#else
   		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-#endif		
+		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);
+  			}
+  		}
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		if (!host->in_bus_reset) {
 			DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",
@@ -1309,12 +1304,10 @@
 
 		/* Finally, we clear the busReset event and reenable
 		 * the busReset interrupt. */
-#ifndef BUSRESET_WORKAROUND
 		spin_lock_irqsave(&ohci->event_lock, flags);
 		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
-#endif
 		event &= ~OHCI1394_selfIDComplete;	
 	}
 
@@ -1966,8 +1959,6 @@
 	cf_put_keyval(&cr, 0x03, 0x00005e);	/* Vendor ID */
 	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */
 	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */
-	cf_put_refer(&cr, 0xd1, 3);		/* IPv4 unit directory */
-	cf_put_refer(&cr, 0xd1, 4);		/* IPv6 unit directory */
 	/* NOTE: Add other unit referers here, and append at bottom */
 	cf_unit_end(&cr);
 
@@ -1980,46 +1971,6 @@
 	cf_put_4bytes(&cr, '9', '4', 0x0, 0x0);
 	cf_unit_end(&cr);
 
-	/* IPv4 unit directory, RFC 2734 */
-	cf_unit_begin(&cr, 3);
-	cf_put_keyval(&cr, 0x12, 0x00005e);	/* Unit spec ID */
-	cf_put_refer(&cr, 0x81, 6);		/* Textual description unit */
-	cf_put_keyval(&cr, 0x13, 0x000001);	/* Unit software version */
-	cf_put_refer(&cr, 0x81, 7);		/* Textual description unit */
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 6);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'A', 'N', 'A');
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 7);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'P', 'v', '4');
-	cf_unit_end(&cr);
-
-	/* IPv6 unit directory, draft-ietf-ipngwg-1394-01.txt */
-	cf_unit_begin(&cr, 4);
-	cf_put_keyval(&cr, 0x12, 0x00005e);	/* Unit spec ID */
-	cf_put_refer(&cr, 0x81, 8);		/* Textual description unit */
-	cf_put_keyval(&cr, 0x13, 0x000002);	/* (Proposed) Unit software version */
-	cf_put_refer(&cr, 0x81, 9);		/* Textual description unit */
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 8);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'A', 'N', 'A');
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 9);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'P', 'v', '6');
-	cf_unit_end(&cr);
-
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
 }
 
@@ -2309,8 +2260,8 @@
 
 		of_node = pci_device_to_OF_node(ohci->dev);
 		if (of_node) {
-			feature_set_firewire_power(of_node, 0);
-			feature_set_firewire_cable_power(of_node, 0);
+			pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0);
+			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0);
 		}
 	}
 #endif /* CONFIG_ALL_PPC */
@@ -2423,7 +2374,7 @@
 	name:		OHCI1394_DRIVER_NAME,
 	id_table:	ohci1394_pci_tbl,
 	probe:		ohci1394_add_one,
-	remove:		ohci1394_remove_one,
+	remove:		__devexit_p(ohci1394_remove_one),
 };
 
 static void __exit ohci1394_cleanup (void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- linux-2.4.16/drivers/ieee1394/pcilynx.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/pcilynx.c	Tue Dec  4 19:25:30 2001
@@ -1637,8 +1637,8 @@
 
 static void __exit pcilynx_cleanup(void)
 {
-        pci_unregister_driver(&lynx_pcidriver);
         hpsb_unregister_lowlevel(&lynx_template);
+	pci_unregister_driver(&lynx_pcidriver);
         PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/sbp2.c linux/drivers/ieee1394/sbp2.c
--- linux-2.4.16/drivers/ieee1394/sbp2.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/sbp2.c	Tue Dec  4 19:25:30 2001
@@ -222,8 +222,25 @@
  *                 when we register our driver.  This change 
  *                 automtically adds hotplug support to the driver.
  *                                 Kristian Hogsberg <hogsberg@users.sf.net>
+ *
+ *      11/17/01 - Various bugfixes/cleanups:
+ *                 * Remember to logout of device in sbp2_disconnect.
+ *                 * If we fail to reconnect to a device after bus reset
+ *                   remember to release unit directory, so the ieee1394
+ *                   knows we no longer manage it.
+ *                 * Unregister scsi hosts in sbp2_remove_host when a
+ *                   hpsb_host goes away.
+ *                 * Remove stupid hack in sbp2_remove_host.
+ *                 * Switched to "manual" module initialization
+ *                   (i.e. not scsi_module.c) and moved sbp2_cleanup
+ *                   moved sbp2scsi_release to sbp2_module_ext.  The
+ *                   release function is called once pr. registered
+ *                   scsi host, but sbp2_cleanup should only be called
+ *                   upon module unload.  Moved much initialization
+ *                   from sbp2scsi_detect to sbp2_module_init.
+ *                                 Kristian Hogsberg <hogsberg@users.sf.net>
  */
-    
+
 
 
 /*
@@ -244,6 +261,7 @@
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -395,7 +413,7 @@
  * Globals
  */
 
-Scsi_Host_Template *global_scsi_tpnt = NULL;
+static Scsi_Host_Template scsi_driver_template;
 
 static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
 
@@ -671,13 +689,13 @@
 static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id,
 					     struct sbp2scsi_host_info *hi)
 {
-	struct list_head *lh;
+	struct list_head *lh, *next;
 	struct sbp2_command_info *command;
 	unsigned long flags;
         
 	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
-		list_for_each(lh, &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);
 
 			/* Release our generic DMA's */
@@ -868,7 +886,6 @@
 		hpsb_unregister_highlevel(sbp2_hl_handle);
 		sbp2_hl_handle = NULL;
 	}
-	return;
 }
 
 static int sbp2_probe(struct unit_directory *ud)
@@ -889,8 +906,10 @@
 	SBP2_DEBUG("sbp2_disconnect");
 	hi = sbp2_find_host_info(ud->ne->host);
 
-	if (hi != NULL)
-		sbp2_remove_device(hi, scsi_id);
+	if (hi != NULL) {
+		sbp2_logout_device(hi, scsi_id);
+ 		sbp2_remove_device(hi, scsi_id);
+	}
 }
 
 static void sbp2_update(struct unit_directory *ud)
@@ -909,12 +928,10 @@
 		 */
 		if (sbp2_login_device(hi, scsi_id)) {
 
-			/* Login failed too... so, just mark him as
-			 * unvalidated, so that he gets cleaned up
-			 * later.
-			 */
+			/* Login failed too, just remove the device. */
 			SBP2_ERR("sbp2_reconnect_device failed!");
 			sbp2_remove_device(hi, scsi_id);
+			hpsb_release_unit_directory(ud);
 			return;
 		}
 	}
@@ -978,7 +995,10 @@
 	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
 
 	/* Register our host with the SCSI stack. */
-	sbp2scsi_register_scsi_host(hi);
+	hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
+	if (hi->scsi_host)
+		hi->scsi_host->hostdata[0] = (unsigned long)hi;
+	scsi_driver_template.present++;
 
 	return;
 }
@@ -1003,13 +1023,12 @@
 }
 
 /*
- * This function is called when the host is removed
+ * This function is called when a host is removed.
  */
 static void sbp2_remove_host(struct hpsb_host *host)
 {
 	struct sbp2scsi_host_info *hi;
 	unsigned long flags;
-	int i;
 
 	SBP2_DEBUG("sbp2_remove_host");
 
@@ -1017,22 +1036,11 @@
 
 	hi = sbp2_find_host_info(host);
 	if (hi != NULL) {
-		/* Here's an annoying hack: we get a disconnect
-		 * callback for each device, so this loop shouldn't be
-		 * necessary.  However, the sbp2 driver receives the
-		 * remove_host callback before the nodemgr, so when we
-		 * get the disconnect callback, we've already freed
-		 * the host.  Thus, we free the devices here...
-		 */
-		for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
-			if (hi->scsi_id[i] != NULL) {
-				sbp2_logout_device(hi, hi->scsi_id[i]);
-				sbp2_remove_device(hi, hi->scsi_id[i]);
-			}
-		}
 		sbp2util_remove_request_packet_pool(hi);
 		sbp2_host_count--;
 		list_del(&hi->list);
+		scsi_unregister(hi->scsi_host);
+		scsi_driver_template.present--;
 		kfree(hi);
 	}
 	else
@@ -1203,10 +1211,7 @@
 	 */
 	if (sbp2_login_device(hi, scsi_id)) {
 
-		/*
-		 * Login failed... so, just mark him as unvalidated, so
-		 * that he gets cleaned up later.
-		 */
+		/* Login failed, just remove the device. */
 		SBP2_ERR("sbp2_login_device failed");
 		sbp2_remove_device(hi, scsi_id);
 		return -EBUSY;
@@ -1231,11 +1236,13 @@
 }
 
 /*
- * This function removes (cleans-up after) any unvalidated sbp2 devices
+ * This function removes an sbp2 device from the sbp2scsi_host_info struct.
  */
 static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
 			       struct scsi_id_instance_data *scsi_id)
 {
+	SBP2_DEBUG("sbp2_remove_device");
+
 	/* Complete any pending commands with selection timeout */
 	sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT);
        			
@@ -1276,8 +1283,7 @@
 		SBP2_DMA_FREE("single logout orb");
 	}
 
-	SBP2_DEBUG("Unvalidated SBP-2 device removed, SCSI ID = %d", 
-		   scsi_id->id);
+	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
 	hi->scsi_id[scsi_id->id] = NULL;
 	kfree(scsi_id);
 }
@@ -1381,7 +1387,7 @@
 
 	/*
 	 * Check status
-	 */				       
+	 */
 	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
 	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
 	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
@@ -1687,9 +1693,9 @@
 	scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],
 					(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
 
-	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [0x%02x/%u]",
+	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
 		 NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code],
-		 scsi_id->max_payload_size, 1 << ((u32)scsi_id->max_payload_size + 2));
+		 1 << ((u32)scsi_id->max_payload_size + 2));
 
 	return(0);
 }
@@ -2860,127 +2866,111 @@
 	return(0);
 }
 
-/*
- * This routine is called at setup (init) and does nothing. Not used here.   =)
- */
-void sbp2scsi_setup( char *str, int *ints) 
-{
-	SBP2_DEBUG("sbp2scsi_setup");
-	return;
-}
-
-/*
- * This is our detection routine, and is where we init everything.
- */
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt) 
 {
 	SBP2_DEBUG("sbp2scsi_detect");
 
-	global_scsi_tpnt = tpnt;
+	/*
+	 * Call sbp2_init to register with the ieee1394 stack.  This
+	 * results in a callback to sbp2_add_host for each ieee1394
+	 * host controller currently registered, and for each of those
+	 * we register a scsi host with the scsi stack.
+	 */
+	sbp2_init();
+
+	/* We return the number of hosts registered. */
+	return sbp2_host_count;
+}
+
+MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
+MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
+MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
+MODULE_LICENSE("GPL");
+
+/* SCSI host template */
+static Scsi_Host_Template scsi_driver_template = {
+	name:		"IEEE-1394 SBP-2 protocol driver",
+	detect:		sbp2scsi_detect,
+	queuecommand:	sbp2scsi_queuecommand,
+	abort:		sbp2scsi_abort,
+	reset:		sbp2scsi_reset,
+	bios_param:	sbp2scsi_biosparam,
+	can_queue:	SBP2SCSI_MAX_OUTSTANDING_CMDS,
+	this_id:	-1,
+	sg_tablesize:	SBP2_MAX_SG_ELEMENTS,
+	cmd_per_lun:	SBP2SCSI_MAX_CMDS_PER_LUN,
+	use_clustering:	SBP2_CLUSTERING,
+	emulated:	1,
+
+	module:         THIS_MODULE,
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
-	global_scsi_tpnt->proc_name = SBP2_DEVICE_NAME;
+	proc_name: SBP2_DEVICE_NAME
 #endif
+};
+
+static int sbp2_module_init(void)
+{
+	SBP2_DEBUG("sbp2_module_init");
+
 	/*
 	 * Module load option for force one command at a time
 	 */
 	if (serialize_io) {
 		SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
-		global_scsi_tpnt->can_queue = 1;
-		global_scsi_tpnt->cmd_per_lun = 1;
+		scsi_driver_template.can_queue = 1;
+		scsi_driver_template.cmd_per_lun = 1;
 	}
 
 	/*
-	 * Module load option to limit max size of requests from the scsi drivers
+	 * Module load option to limit max size of requests from the
+	 * scsi drivers
 	 */
 	if (no_large_packets) {
-		SBP2_ERR("Driver forced to limit max transfer size (no_large_packets = 1)");
-		global_scsi_tpnt->sg_tablesize = 0x1f;
-		global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING;
+		SBP2_ERR("Driver forced to limit max transfer size "
+			 "(no_large_packets = 1)");
+		scsi_driver_template.sg_tablesize = 0x1f;
+		scsi_driver_template.use_clustering = DISABLE_CLUSTERING;
 	}
 
 	if (mode_sense_hack) {
 		SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)");
 	}
 
-	sbp2_init();
-
-	if (!sbp2_host_count) {
-		SBP2_ERR("Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2...");
+	/*
+	 * Ideally we would register our scsi_driver_template with the
+	 * scsi stack and after that register with the ieee1394 stack
+	 * and process the add_host callbacks.  However, the detect
+	 * function in the scsi host template requires that we find at
+	 * least one host, so we "nest" the registrations by calling
+	 * sbp2_init from the detect function.
+	 */
+	if (scsi_register_module(MODULE_SCSI_HA, &scsi_driver_template) ||
+	    !scsi_driver_template.present) {
+		SBP2_ERR("Please load the lower level IEEE-1394 driver "
+			 "(e.g. ohci1394) before sbp2...");
 		sbp2_cleanup();
+		return -ENODEV;
 	}
 
-	/*
-	 * Since we are returning this count, it means that sbp2 must be
-	 * loaded "after" the host adapter module...
-	 */
-	return(sbp2_host_count);
+	return 0;
 }
 
-/*
- * This function is called from sbp2_add_host, and is where we register
- * our scsi host
- */
-static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi)
+static void __exit sbp2_module_exit(void)
 {
-	struct Scsi_Host *shpnt = NULL;
-
-	SBP2_DEBUG("sbp2scsi_register_scsi_host");
-	SBP2_DEBUG("sbp2scsi_host_info = %p", hi);
+	SBP2_DEBUG("sbp2_module_exit");
 
 	/*
-	 * Let's register with the scsi stack
+	 * On module unload we unregister with the ieee1394 stack
+	 * which results in remove_host callbacks for all ieee1394
+	 * host controllers.  In the callbacks we unregister the
+	 * corresponding scsi hosts.
 	 */
-	if (global_scsi_tpnt) {
-
-		shpnt = scsi_register (global_scsi_tpnt, sizeof(void *));
-
-		/*
-		 * If successful, save off a context (to be used when SCSI
-		 * commands are received)
-		 */
-		if (shpnt) {
-			shpnt->hostdata[0] = (unsigned long)hi;
-		}
-	}
-
-	return;
-}
-
-/* Called when our module is released */
-static int sbp2scsi_release(struct Scsi_Host *host)
-{
-	SBP2_DEBUG("sbp2scsi_release");
 	sbp2_cleanup();
-	return(0);
-}
 
-/* Called for contents of procfs */
-static const char *sbp2scsi_info (struct Scsi_Host *host)
-{
-	return "IEEE-1394 SBP-2 protocol driver";
+	if (scsi_unregister_module(MODULE_SCSI_HA, &scsi_driver_template))
+		SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
 }
 
-MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
-
-/* SCSI host template */
-static Scsi_Host_Template driver_template = {
-	name:		"IEEE1394 SBP-2",
-	detect:		sbp2scsi_detect,
-	release:	sbp2scsi_release,
-	info:		sbp2scsi_info,
-	queuecommand:	sbp2scsi_queuecommand,
-	abort:		sbp2scsi_abort,
-	reset:		sbp2scsi_reset,
-	bios_param:	sbp2scsi_biosparam,
-	can_queue:	SBP2SCSI_MAX_OUTSTANDING_CMDS,
-	this_id:	-1,
-	sg_tablesize:	SBP2_MAX_SG_ELEMENTS,
-	cmd_per_lun:	SBP2SCSI_MAX_CMDS_PER_LUN,
-	use_clustering:	SBP2_CLUSTERING,
-	emulated:	1
-};
-
-#include "../scsi/scsi_module.c"
+module_init(sbp2_module_init);
+module_exit(sbp2_module_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/sbp2.h linux/drivers/ieee1394/sbp2.h
--- linux-2.4.16/drivers/ieee1394/sbp2.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/sbp2.h	Tue Dec  4 19:25:30 2001
@@ -403,6 +403,13 @@
 	spinlock_t sbp2_request_packet_lock;
 
 	/*
+	 * This is the scsi host we register with the scsi mid level.
+	 * We keep a reference to it here, so we can unregister it
+	 * when the hpsb_host is removed.
+	 */
+	struct Scsi_Host *scsi_host;
+
+	/*
 	 * Lists keeping track of inuse/free sbp2_request_packets. These structures are
 	 * used for sending out sbp2 command and agent reset packets. We initially create
 	 * a pool of request packets so that we don't have to do any kmallocs while in critical
@@ -498,7 +505,6 @@
 /*
  * Scsi interface related prototypes
  */
-static const char *sbp2scsi_info (struct Scsi_Host *host);
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 void sbp2scsi_setup(char *str, int *ints);
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
@@ -509,6 +515,5 @@
 					   u32 status);
 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 *));
-static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi);
 
 #endif /* SBP2_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- linux-2.4.16/drivers/ieee1394/video1394.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/video1394.c	Tue Dec  4 19:25:30 2001
@@ -47,6 +47,8 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -95,6 +97,7 @@
         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 
 					variable sized packets only ! */
 	int ctrlClear;
@@ -102,8 +105,8 @@
 	int cmdPtr;
 	int ctxMatch;
 	wait_queue_head_t waitq;
-        spinlock_t lock;
-    unsigned int syt_offset;
+	spinlock_t lock;
+	unsigned int syt_offset;
 	int flags;
 };
 
@@ -304,6 +307,8 @@
 
 	if ((*d)->buffer_status)
 		kfree((*d)->buffer_status);
+	if ((*d)->buffer_time)
+		kfree((*d)->buffer_time);
 	if ((*d)->last_used_cmd)
 		kfree((*d)->last_used_cmd);
 	if ((*d)->next_buffer)
@@ -437,6 +442,8 @@
 
 	d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
 				   GFP_KERNEL);
+	d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval),
+				   GFP_KERNEL);
 	d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int),
 				   GFP_KERNEL);
 	d->next_buffer = kmalloc(d->num_desc * sizeof(int),
@@ -447,6 +454,11 @@
 		free_dma_iso_ctx(&d);
 		return NULL;
 	}
+	if (d->buffer_time == NULL) {
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_time");
+		free_dma_iso_ctx(&d);
+		return NULL;
+	}
 	if (d->last_used_cmd == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd");
 		free_dma_iso_ctx(&d);
@@ -458,6 +470,7 @@
 		return NULL;
 	}
 	memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
+	memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval));
 	memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int));
 	memset(d->next_buffer, -1, d->num_desc * sizeof(int));
 	
@@ -604,6 +617,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+			get_fast_time(&d->buffer_time[i]);
 		}
 	}
 	spin_unlock(&d->lock);
@@ -876,9 +890,23 @@
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
+
+		/* if channel < 0, find lowest available one */
+		if (v.channel < 0) {
+		    mask = (u64)0x1;
+		    for (i=0; i<ISO_CHANNELS; i++) {
+			if (!(ohci->ISO_channel_usage & mask)) {
+			    v.channel = i;
+			    PRINT(KERN_INFO, ohci->id, "Found free channel %d\n", i);
+			    break;
+			}
+			mask = mask << 1;
+		    }
+		}
+		    
 		if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
 			PRINT(KERN_ERR, ohci->id, 
-			      "Iso channel %d out of bound", v.channel);
+			      "Iso channel %d out of bounds", v.channel);
 			return -EFAULT;
 		}
 		mask = (u64)0x1<<v.channel;
@@ -1092,6 +1120,7 @@
 		
 	}
 	case VIDEO1394_LISTEN_WAIT_BUFFER:
+	case VIDEO1394_LISTEN_POLL_BUFFER:
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
@@ -1120,6 +1149,12 @@
 			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
 			break;
 		case VIDEO1394_BUFFER_QUEUED:
+			if (cmd == VIDEO1394_LISTEN_POLL_BUFFER) {
+			    /* for polling, return error code EINTR */
+			    spin_unlock_irqrestore(&d->lock, flags);
+			    return -EINTR;
+			}
+
 #if 1
 			while(d->buffer_status[v.buffer]!=
 			      VIDEO1394_BUFFER_READY) {
@@ -1147,6 +1182,10 @@
 			return -EFAULT;
 		}
 
+		/* set time of buffer */
+		v.filltime = d->buffer_time[v.buffer];
+//		printk("Buffer %d time %d\n", v.buffer, (d->buffer_time[v.buffer]).tv_usec);
+
 		/*
 		 * Look ahead to see how many more buffers have been received
 		 */
@@ -1596,7 +1635,8 @@
 {
 	struct ti_ohci *ohci;
 	unsigned long flags;
-	struct list_head *lh;
+	struct list_head *lh, *next;
+	struct video_card *p;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
@@ -1605,14 +1645,11 @@
 	ohci = (struct ti_ohci *)host->hostdata;
 
         spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p ->ohci == ohci) {
-				remove_card(p);
-				break;
-			}
+	list_for_each_safe(lh, next, &video1394_cards) {
+		p = list_entry(lh, struct video_card, list);
+		if (p->ohci == ohci) {
+			remove_card(p);
+			break;
 		}
 	}
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
@@ -1652,7 +1689,7 @@
 	devfs_unregister(devfs_handle);
 	devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
 
-	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module\n");
+	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
 }
 
 static int __init video1394_init_module (void)
@@ -1678,6 +1715,7 @@
 		return -ENOMEM;
 	}
 
+	PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/ieee1394/video1394.h linux/drivers/ieee1394/video1394.h
--- linux-2.4.16/drivers/ieee1394/video1394.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/ieee1394/video1394.h	Tue Dec  4 19:25:30 2001
@@ -35,11 +35,12 @@
 	VIDEO1394_LISTEN_CHANNEL = 0,
 	VIDEO1394_UNLISTEN_CHANNEL,
 	VIDEO1394_LISTEN_QUEUE_BUFFER,
-	VIDEO1394_LISTEN_WAIT_BUFFER,
+	VIDEO1394_LISTEN_WAIT_BUFFER,  // wait until buffer is ready
 	VIDEO1394_TALK_CHANNEL,
 	VIDEO1394_UNTALK_CHANNEL,
 	VIDEO1394_TALK_QUEUE_BUFFER,
-	VIDEO1394_TALK_WAIT_BUFFER
+	VIDEO1394_TALK_WAIT_BUFFER,
+	VIDEO1394_LISTEN_POLL_BUFFER   // return immediately with -EINTR if not ready
 };
 
 #define VIDEO1394_SYNC_FRAMES          0x00000001
@@ -47,7 +48,7 @@
 #define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
 
 struct video1394_mmap {
-	unsigned int channel;
+	int channel;			/* -1 to find an open channel in LISTEN/TALK */
 	unsigned int sync_tag;
 	unsigned int nb_buffers;
 	unsigned int buf_size;
@@ -69,6 +70,7 @@
 struct video1394_wait {
 	unsigned int channel;
 	unsigned int buffer;
+	struct timeval filltime;	/* time of buffer full */
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- linux-2.4.16/drivers/isdn/Config.in	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/Config.in	Sun Dec  9 19:23:10 2001
@@ -42,6 +42,7 @@
    fi
    bool '  HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
    bool '  HiSax Support for US NI1' CONFIG_HISAX_NI1
+   int  '  Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
    comment '  HiSax supported cards'
    bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
    bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
@@ -81,6 +82,7 @@
    dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
    dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
    dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
 fi
 endmenu
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h
--- linux-2.4.16/drivers/isdn/act2000/act2000.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/act2000/act2000.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: act2000.h,v 1.8.6.3 2001/09/23 22:24:32 kai Exp $
+/* $Id: act2000.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/act2000/act2000_isa.c linux/drivers/isdn/act2000/act2000_isa.c
--- linux-2.4.16/drivers/isdn/act2000/act2000_isa.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/act2000/act2000_isa.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.c,v 1.11.6.3 2001/09/23 22:24:32 kai Exp $
+/* $Id: act2000_isa.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/act2000/act2000_isa.h linux/drivers/isdn/act2000/act2000_isa.h
--- linux-2.4.16/drivers/isdn/act2000/act2000_isa.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/act2000/act2000_isa.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
+/* $Id: act2000_isa.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/act2000/capi.c linux/drivers/isdn/act2000/capi.c
--- linux-2.4.16/drivers/isdn/act2000/capi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/act2000/capi.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
+/* $Id: capi.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  * CAPI encoder/decoder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/act2000/capi.h linux/drivers/isdn/act2000/capi.h
--- linux-2.4.16/drivers/isdn/act2000/capi.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/act2000/capi.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capi.h,v 1.6.6.2 2001/09/23 22:24:32 kai Exp $
+/* $Id: capi.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c
--- linux-2.4.16/drivers/isdn/act2000/module.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/act2000/module.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $
+/* $Id: module.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/avm_cs.c linux/drivers/isdn/avmb1/avm_cs.c
--- linux-2.4.16/drivers/isdn/avmb1/avm_cs.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/avm_cs.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $
+/* $Id: avm_cs.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * A PCMCIA client driver for AVM B1/M1/M2
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h
--- linux-2.4.16/drivers/isdn/avmb1/avmcard.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/avmcard.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: avmcard.h,v 1.8.6.4 2001/09/23 22:24:33 kai Exp $
+/* $Id: avmcard.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Copyright 1999 by Carsten Paeth <calle@calle.de>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c
--- linux-2.4.16/drivers/isdn/avmb1/b1.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/b1.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: b1.c,v 1.20.6.7 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Common module for AVM B1 cards.
  * 
@@ -27,7 +27,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.20.6.7 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- linux-2.4.16/drivers/isdn/avmb1/b1dma.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/b1dma.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: b1dma.c,v 1.11.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1dma.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
@@ -32,7 +32,7 @@
 #error FIXME: driver requires 32-bit platform
 #endif
 
-static char *revision = "$Revision: 1.11.6.8 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c
--- linux-2.4.16/drivers/isdn/avmb1/b1isa.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/b1isa.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: b1isa.c,v 1.10.6.6 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1isa.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
@@ -24,7 +24,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.10.6.6 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- linux-2.4.16/drivers/isdn/avmb1/b1pci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/b1pci.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: b1pci.c,v 1.29.6.5 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1pci.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
@@ -26,7 +26,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.29.6.5 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c
--- linux-2.4.16/drivers/isdn/avmb1/b1pcmcia.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/b1pcmcia.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: b1pcmcia.c,v 1.12.6.5 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1pcmcia.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
@@ -25,7 +25,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.12.6.5 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- linux-2.4.16/drivers/isdn/avmb1/c4.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/c4.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: c4.c,v 1.20.6.11 2001/09/23 22:24:33 kai Exp $
+/* $Id: c4.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Module for AVM C4 & C2 card.
  * 
@@ -29,7 +29,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.11 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- linux-2.4.16/drivers/isdn/avmb1/capi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capi.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.44.6.15 2001/09/28 08:05:29 kai Exp $
+/* $Id: capi.c,v 1.1.4.2 2001/12/09 18:45:13 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
@@ -45,7 +45,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.44.6.15 $";
+static char *revision = "$Revision: 1.1.4.2 $";
 
 MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
 MODULE_AUTHOR("Carsten Paeth");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capicmd.h linux/drivers/isdn/avmb1/capicmd.h
--- linux-2.4.16/drivers/isdn/avmb1/capicmd.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capicmd.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capicmd.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $
+/* $Id: capicmd.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * CAPI 2.0 Interface for Linux
  * 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h
--- linux-2.4.16/drivers/isdn/avmb1/capidev.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capidev.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capidev.h,v 1.6.6.2 2001/09/23 22:24:33 kai Exp $
+/* $Id: capidev.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- linux-2.4.16/drivers/isdn/avmb1/capidrv.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capidrv.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capidrv.c,v 1.39.6.7 2001/09/23 22:24:33 kai Exp $
+/* $Id: capidrv.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
@@ -35,7 +35,7 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.39.6.7 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 static int debugmode = 0;
 
 MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capidrv.h linux/drivers/isdn/avmb1/capidrv.h
--- linux-2.4.16/drivers/isdn/avmb1/capidrv.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capidrv.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
+/* $Id: capidrv.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c
--- linux-2.4.16/drivers/isdn/avmb1/capifs.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capifs.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capifs.c,v 1.14.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: capifs.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Copyright 2000 by Carsten Paeth <calle@calle.de>
  *
@@ -32,7 +32,7 @@
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
 
-static char *revision = "$Revision: 1.14.6.8 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 struct capifs_ncci {
 	struct inode *inode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capifs.h linux/drivers/isdn/avmb1/capifs.h
--- linux-2.4.16/drivers/isdn/avmb1/capifs.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capifs.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capifs.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $
+/* $Id: capifs.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Copyright 2000 by Carsten Paeth <calle@calle.de>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capilli.h linux/drivers/isdn/avmb1/capilli.h
--- linux-2.4.16/drivers/isdn/avmb1/capilli.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capilli.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capilli.h,v 1.4.8.1 2001/09/23 22:24:33 kai Exp $
+/* $Id: capilli.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Kernel CAPI 2.0 Driver Interface for Linux
  * 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c
--- linux-2.4.16/drivers/isdn/avmb1/capiutil.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capiutil.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capiutil.c,v 1.13.6.4 2001/09/23 22:24:33 kai Exp $
+/* $Id: capiutil.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * CAPI 2.0 convert capi message to capi message struct
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/capiutil.h linux/drivers/isdn/avmb1/capiutil.h
--- linux-2.4.16/drivers/isdn/avmb1/capiutil.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/capiutil.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capiutil.h,v 1.5.6.2 2001/09/23 22:24:33 kai Exp $
+/* $Id: capiutil.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * CAPI 2.0 defines & types
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- linux-2.4.16/drivers/isdn/avmb1/kcapi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/kcapi.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: kcapi.c,v 1.21.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: kcapi.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
@@ -33,7 +33,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.21.6.8 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c
--- linux-2.4.16/drivers/isdn/avmb1/t1isa.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/t1isa.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: t1isa.c,v 1.16.6.7 2001/09/23 22:24:34 kai Exp $
+/* $Id: t1isa.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
@@ -25,7 +25,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.16.6.7 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- linux-2.4.16/drivers/isdn/avmb1/t1pci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/avmb1/t1pci.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: t1pci.c,v 1.13.6.6 2001/09/23 22:24:34 kai Exp $
+/* $Id: t1pci.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
@@ -26,7 +26,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.13.6.6 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c
--- linux-2.4.16/drivers/isdn/divert/divert_procfs.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/divert/divert_procfs.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
+/* $Id: divert_procfs.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Filesystem handling for the diversion supplementary services.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c
--- linux-2.4.16/drivers/isdn/divert/isdn_divert.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/divert/isdn_divert.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
+/* $Id: isdn_divert.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * DSS1 main diversion supplementary handling for i4l.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/divert/isdn_divert.h linux/drivers/isdn/divert/isdn_divert.h
--- linux-2.4.16/drivers/isdn/divert/isdn_divert.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/divert/isdn_divert.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
+/* $Id: isdn_divert.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Header for the diversion supplementary ioctl interface.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c
--- linux-2.4.16/drivers/isdn/eicon/common.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/common.c	Thu Dec  6 19:16:30 2001
@@ -808,7 +808,9 @@
 	
 	while(i--)
 	{
-		DivaDoCardDpc(card++);
+            if (card->state == DIA_RUNNING)
+		DivaDoCardDpc(card);
+            card++;
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h
--- linux-2.4.16/drivers/isdn/eicon/eicon.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon.h	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.23.6.5 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_dsp.h linux/drivers/isdn/eicon/eicon_dsp.h
--- linux-2.4.16/drivers/isdn/eicon/eicon_dsp.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_dsp.h	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.7.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_dsp.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  * DSP definitions
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c
--- linux-2.4.16/drivers/isdn/eicon/eicon_idi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_idi.c	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.41.6.4 2001/11/06 20:58:29 kai Exp $
+/* $Id: eicon_idi.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  * IDI interface 
@@ -25,7 +25,7 @@
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.41.6.4 $";
+char *eicon_idi_revision = "$Revision: 1.1.4.1 $";
 
 eicon_manifbuf *manbuf;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_idi.h linux/drivers/isdn/eicon/eicon_idi.h
--- linux-2.4.16/drivers/isdn/eicon/eicon_idi.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_idi.h	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.11.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_idi.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN lowlevel-module for the Eicon active cards.
  * IDI-Interface
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c
--- linux-2.4.16/drivers/isdn/eicon/eicon_io.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_io.c	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.13.6.2 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_io.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Code for communicating with hardware.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c
--- linux-2.4.16/drivers/isdn/eicon/eicon_isa.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_isa.c	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.16.6.2 2001/11/06 20:58:29 kai Exp $
+/* $Id: eicon_isa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for old ISA cards.
@@ -20,7 +20,7 @@
 #define release_shmem release_region
 #define request_shmem request_region
 
-char *eicon_isa_revision = "$Revision: 1.16.6.2 $";
+char *eicon_isa_revision = "$Revision: 1.1.4.1 $";
 
 #undef EICON_MCA_DEBUG
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_isa.h linux/drivers/isdn/eicon/eicon_isa.h
--- linux-2.4.16/drivers/isdn/eicon/eicon_isa.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_isa.h	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.10.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_isa.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c
--- linux-2.4.16/drivers/isdn/eicon/eicon_mod.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_mod.c	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.37.6.6 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_mod.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  * 
@@ -44,7 +44,7 @@
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.37.6.6 $";
+static char *eicon_revision = "$Revision: 1.1.4.1 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
@@ -1550,7 +1550,7 @@
             	};
 	};
 	/* all adapter flavors checked without match, finito with:            */
-        return ENODEV;
+        return -ENODEV;
 };
 
 
@@ -1597,14 +1597,14 @@
 				membase = cards_membase;
 			} else {
 				if (membase != cards_membase)
-					return ENODEV;
+					return -ENODEV;
 			};
 			cards_irq=irq_array[((adf_pos0 & 0xC)>>2)];
 			if (irq == -1) { 
 				irq = cards_irq;
 			} else {
 				if (irq != cards_irq)
-					return ENODEV;
+					return -ENODEV;
 			};
 			cards_io= 0xC00 + ((adf_pos0>>4)*0x10);
 			type = EICON_CTYPE_ISAPRI; 
@@ -1616,14 +1616,14 @@
 				membase = cards_membase;
 			} else {
 				if (membase != cards_membase)
-					return ENODEV;
+					return -ENODEV;
 			};
 			cards_irq=irq_array[((adf_pos0 & 0xC)>>2)];
 			if (irq == -1) { 
 				irq = cards_irq;
 			} else {
 				if (irq != cards_irq)
-					return ENODEV;
+					return -ENODEV;
 			};
 
 			cards_io= 0xC00 + ((adf_pos0>>4)*0x10);
@@ -1637,12 +1637,12 @@
 				irq = cards_irq;
 			} else {
 				if (irq != cards_irq)
-					return ENODEV;
+					return -ENODEV;
 			};
 			type = 0; 
 			break;
 		default:
-			return  ENODEV;
+			return -ENODEV;
 	};
 	/* matching membase & irq */
 	if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { 
@@ -1661,7 +1661,7 @@
 			cards->mca_slot+1);
 		return  0 ; /* eicon_addcard added a card */
 	} else {
-		return ENODEV;
+		return -ENODEV;
 	};
 };
 #endif /* CONFIG_MCA */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c
--- linux-2.4.16/drivers/isdn/eicon/eicon_pci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_pci.c	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.15.6.3 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for PCI cards.
@@ -24,7 +24,7 @@
 #include "adapter.h"
 #include "uxio.h"
 
-char *eicon_pci_revision = "$Revision: 1.15.6.3 $";
+char *eicon_pci_revision = "$Revision: 1.1.4.1 $";
 
 #if CONFIG_PCI	         /* intire stuff is only for PCI */
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/eicon/eicon_pci.h linux/drivers/isdn/eicon/eicon_pci.h
--- linux-2.4.16/drivers/isdn/eicon/eicon_pci.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/eicon/eicon_pci.h	Thu Dec  6 19:16:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.h,v 1.6.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_pci.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards (PCI part).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- linux-2.4.16/drivers/isdn/hisax/Makefile	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/Makefile	Sun Dec  9 19:23:10 2001
@@ -4,9 +4,13 @@
 
 O_TARGET	  := vmlinux-obj.o
 
+# Define maximum number of cards
+
+EXTRA_CFLAGS      += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
+
 # Objects that export symbols.
 
-export-objs	  := config.o fsm.o
+export-objs	  := config.o fsm.o hisax_isac.o
 
 # Multipart objects.
 
@@ -58,6 +62,7 @@
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)	+= sedlbauer_cs.o
 obj-$(CONFIG_HISAX_ELSA_CS)		+= elsa_cs.o
 obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o
+obj-$(CONFIG_HISAX_FRITZ_PCIPNP)        += hisax_isac.o hisax_fcpcipnp.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.16/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c
--- linux-2.4.16/drivers/isdn/hisax/amd7930.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/amd7930.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: amd7930.c,v 1.5.6.4 2001/09/23 22:24:46 kai Exp $
+/* $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
  *
@@ -98,7 +98,7 @@
 #include "rawhdlc.h"
 #include <linux/interrupt.h>
 
-static const char *amd7930_revision = "$Revision: 1.5.6.4 $";
+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
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c
--- linux-2.4.16/drivers/isdn/hisax/arcofi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/arcofi.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: arcofi.c,v 1.12.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: arcofi.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Ansteuerung ARCOFI 2165
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/arcofi.h linux/drivers/isdn/hisax/arcofi.h
--- linux-2.4.16/drivers/isdn/hisax/arcofi.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/arcofi.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: arcofi.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Ansteuerung ARCOFI 2165
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c
--- linux-2.4.16/drivers/isdn/hisax/asuscom.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/asuscom.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: asuscom.c,v 1.11.6.3 2001/09/23 22:24:46 kai Exp $
+/* $Id: asuscom.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
  *
@@ -22,7 +22,7 @@
 
 extern const char *CardType[];
 
-const char *Asuscom_revision = "$Revision: 1.11.6.3 $";
+const char *Asuscom_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- linux-2.4.16/drivers/isdn/hisax/avm_a1.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/avm_a1.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: avm_a1.c,v 2.13.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: avm_a1.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for AVM A1 (Fritz) isdn cards
  *
@@ -18,7 +18,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static const char *avm_revision = "$Revision: 2.13.6.2 $";
+static const char *avm_revision = "$Revision: 1.1.4.1 $";
 
 #define	 AVM_A1_STAT_ISAC	0x01
 #define	 AVM_A1_STAT_HSCX	0x02
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c
--- linux-2.4.16/drivers/isdn/hisax/avm_a1p.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/avm_a1p.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: avm_a1p.c,v 2.7.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: avm_a1p.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for the following AVM cards:
  * A1 PCMCIA
@@ -57,7 +57,7 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static const char *avm_revision = "$Revision: 2.7.6.2 $";
+static const char *avm_revision = "$Revision: 1.1.4.1 $";
 
 static inline u_char
 ReadISAC(struct IsdnCardState *cs, u_char offset)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c
--- linux-2.4.16/drivers/isdn/hisax/avm_pci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/avm_pci.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: avm_pci.c,v 1.22.6.6 2001/09/23 22:24:46 kai Exp $
+/* $Id: avm_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
  *
@@ -22,7 +22,7 @@
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.22.6.6 $";
+static const char *avm_pci_rev = "$Revision: 1.1.4.1 $";
 
 #define  AVM_FRITZ_PCI		1
 #define  AVM_FRITZ_PNP		2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c
--- linux-2.4.16/drivers/isdn/hisax/bkm_a4t.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/bkm_a4t.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a4t.c,v 1.13.6.6 2001/09/23 22:24:46 kai Exp $
+/* $Id: bkm_a4t.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for T-Berkom A4T
  *
@@ -24,7 +24,7 @@
 
 extern const char *CardType[];
 
-const char *bkm_a4t_revision = "$Revision: 1.13.6.6 $";
+const char *bkm_a4t_revision = "$Revision: 1.1.4.1 $";
 
 
 static inline u_char
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c
--- linux-2.4.16/drivers/isdn/hisax/bkm_a8.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/bkm_a8.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.14.6.7 2001/09/23 22:24:46 kai Exp $
+/* $Id: bkm_a8.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for Scitel Quadro (4*S0, passive)
  *
@@ -28,7 +28,7 @@
 
 extern const char *CardType[];
 
-const char sct_quadro_revision[] = "$Revision: 1.14.6.7 $";
+const char sct_quadro_revision[] = "$Revision: 1.1.4.1 $";
 
 static const char *sct_quadro_subtypes[] =
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/bkm_ax.h linux/drivers/isdn/hisax/bkm_ax.h
--- linux-2.4.16/drivers/isdn/hisax/bkm_ax.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/bkm_ax.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $
+/* $Id: bkm_ax.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- linux-2.4.16/drivers/isdn/hisax/callc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/callc.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.51.6.6 2001/09/23 22:24:46 kai Exp $
+/* $Id: callc.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Author       Karsten Keil
  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
@@ -26,7 +26,7 @@
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif	/* MODULE */
 
-const char *lli_revision = "$Revision: 2.51.6.6 $";
+const char *lli_revision = "$Revision: 1.1.4.1 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c
--- linux-2.4.16/drivers/isdn/hisax/cert.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/cert.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: cert.c,v 2.3.6.3 2001/09/23 22:24:47 kai Exp $
+/* $Id: cert.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Author       Karsten Keil
  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- linux-2.4.16/drivers/isdn/hisax/config.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/config.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: config.c,v 2.57.6.20 2001/09/23 22:24:47 kai Exp $
+/* $Id: config.c,v 1.1.4.5 2001/12/09 19:19:26 kai Exp $
  *
  * Author       Karsten Keil
  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
@@ -336,27 +336,19 @@
 	NULL, \
 }
 
-#define EMPTY_CARD	{0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
-
-struct IsdnCard cards[] = {
+struct IsdnCard cards[HISAX_MAX_CARDS] = {
 	FIRST_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
 };
 
-static char HiSaxID[64] __devinitdata = { 0, };
+#define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
+static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, };
 
 char *HiSax_id __devinitdata = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
-static int type[8] __devinitdata = { 0, };
-static int protocol[8] __devinitdata = { 0, };
-static int io[8] __devinitdata = { 0, };
+static int type[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io[HISAX_MAX_CARDS] __devinitdata = { 0, };
 #undef IO0_IO1
 #ifdef CONFIG_HISAX_16_3
 #define IO0_IO1
@@ -366,25 +358,27 @@
 #define IO0_IO1
 #endif
 #ifdef IO0_IO1
-static int io0[8] __devinitdata = { 0, };
-static int io1[8] __devinitdata = { 0, };
+static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, };
 #endif
-static int irq[8] __devinitdata = { 0, };
-static int mem[8] __devinitdata = { 0, };
+static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
 static char *id __devinitdata = HiSaxID;
 
+#define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i"
+
 MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
 MODULE_AUTHOR("Karsten Keil");
 MODULE_LICENSE("GPL");
-MODULE_PARM(type, "1-8i");
-MODULE_PARM(protocol, "1-8i");
-MODULE_PARM(io, "1-8i");
-MODULE_PARM(irq, "1-8i");
-MODULE_PARM(mem, "1-8i");
+MODULE_PARM(type, PARM_PARA);
+MODULE_PARM(protocol, PARM_PARA);
+MODULE_PARM(io, PARM_PARA);
+MODULE_PARM(irq, PARM_PARA);
+MODULE_PARM(mem, PARM_PARA);
 MODULE_PARM(id, "s");
 #ifdef IO0_IO1
-MODULE_PARM(io0, "1-8i");
-MODULE_PARM(io1, "1-8i");
+MODULE_PARM(io0, PARM_PARA);
+MODULE_PARM(io1, PARM_PARA);
 #endif
 #endif /* MODULE */
 
@@ -448,6 +442,7 @@
 	i = 0;
 	j = 1;
 	while (argc && (i < HISAX_MAX_CARDS)) {
+		cards[i].protocol = DEFAULT_PROTO;
 		if (argc) {
 			cards[i].typ = ints[j];
 			j++;
@@ -475,13 +470,15 @@
 		}
 		i++;
 	}
-	if (str && *str) {
-		strcpy(HiSaxID, str);
-		HiSax_id = HiSaxID;
-	} else {
+  	if (str && *str) {
+		if (strlen(str) < HISAX_IDSIZE)
+			strcpy(HiSaxID, str);
+		else
+			printk(KERN_WARNING "HiSax: ID too long!");
+	} else
 		strcpy(HiSaxID, "HiSax");
-		HiSax_id = HiSaxID;
-	}
+
+	HiSax_id = HiSaxID;
 	return 1;
 }
 
@@ -1396,6 +1393,8 @@
 		if (protocol[i]) {
 			cards[j].protocol = protocol[i];
 			nzproto++;
+		} else {
+			cards[j].protocol = DEFAULT_PROTO;
 		}
 		switch (type[i]) {
 		case ISDN_CTYPE_16_0:
@@ -1473,15 +1472,22 @@
 			} else {
 				/* QUADRO is a 4 BRI card */
 				cards[j++].para[0] = 1;
-				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
-				cards[j].protocol = protocol[i];
-				cards[j++].para[0] = 2;
-				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
-				cards[j].protocol = protocol[i];
-				cards[j++].para[0] = 3;
-				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
-				cards[j].protocol = protocol[i];
-				cards[j].para[0] = 4;
+				/* we need to check if further cards can be added */
+				if (j < HISAX_MAX_CARDS) {
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+					cards[j].protocol = protocol[i];
+					cards[j++].para[0] = 2;
+				}
+				if (j < HISAX_MAX_CARDS) {
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+					cards[j].protocol = protocol[i];
+					cards[j++].para[0] = 3;
+				}
+				if (j < HISAX_MAX_CARDS) {
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+					cards[j].protocol = protocol[i];
+					cards[j].para[0] = 4;
+				}
 			}
 			break;
 		}
@@ -1505,15 +1511,9 @@
 	       nrcards, (nrcards > 1) ? "s" : "");
 
 	/* Install only, if at least one card found */
-	if (!HiSax_inithardware(NULL)) {
-		retval = -EIO;
-		goto out_isdnl1;
-	}
-
+	HiSax_inithardware(NULL);
 	return 0;
 
- out_isdnl1:
-	Isdnl1Free();
  out_tei:
 	TeiFree();
  out_isdnl2:
@@ -1560,6 +1560,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
@@ -1600,6 +1602,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
@@ -1640,6 +1644,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
@@ -1680,6 +1686,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- linux-2.4.16/drivers/isdn/hisax/diva.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/diva.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.25.6.5 2001/09/23 22:24:47 kai Exp $
+/* $Id: diva.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for Eicon.Diehl Diva Family ISDN cards
  *
@@ -27,7 +27,7 @@
 
 extern const char *CardType[];
 
-const char *Diva_revision = "$Revision: 1.25.6.5 $";
+const char *Diva_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- linux-2.4.16/drivers/isdn/hisax/elsa.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/elsa.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 2.26.6.6 2001/09/23 22:24:47 kai Exp $
+/* $Id: elsa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for Elsa isdn cards
  *
@@ -33,7 +33,7 @@
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 2.26.6.6 $";
+const char *Elsa_revision = "$Revision: 1.1.4.1 $";
 const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
  "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/elsa_cs.c linux/drivers/isdn/hisax/elsa_cs.c
--- linux-2.4.16/drivers/isdn/hisax/elsa_cs.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/elsa_cs.c	Sun Dec  9 19:23:10 2001
@@ -72,7 +72,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
 static char *version =
-"elsa_cs.c $Revision: 1.1.2.2 $ $Date: 2001/09/23 22:24:47 $ (K.Lichtenwalder)";
+"elsa_cs.c $Revision: 1.1.4.1 $ $Date: 2001/11/20 14:19:35 $ (K.Lichtenwalder)";
 #else
 #define DEBUG(n, args...)
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c
--- linux-2.4.16/drivers/isdn/hisax/elsa_ser.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/elsa_ser.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: elsa_ser.c,v 2.10.6.4 2001/09/23 22:24:47 kai Exp $
+/* $Id: elsa_ser.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * stuff for the serial modem on ELSA cards
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c
--- linux-2.4.16/drivers/isdn/hisax/fsm.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/fsm.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
+/* $Id: fsm.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * Finite state machine
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/fsm.h linux/drivers/isdn/hisax/fsm.h
--- linux-2.4.16/drivers/isdn/hisax/fsm.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/fsm.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
+/* $Id: fsm.h,v 1.1.2.1 2001/11/20 14:19:35 kai Exp $
  *
  * Finite state machine
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c
--- linux-2.4.16/drivers/isdn/hisax/gazel.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/gazel.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: gazel.c,v 2.11.6.7 2001/09/23 22:24:47 kai Exp $
+/* $Id: gazel.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for Gazel isdn cards
  *
@@ -22,7 +22,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.11.6.7 $";
+const char *gazel_revision = "$Revision: 1.1.4.1 $";
 
 #define R647      1
 #define R685      2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- linux-2.4.16/drivers/isdn/hisax/hfc_2bds0.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.15.6.3 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bds0.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * specific routines for CCD's HFC 2BDS0
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_2bds0.h linux/drivers/isdn/hisax/hfc_2bds0.h
--- linux-2.4.16/drivers/isdn/hisax/hfc_2bds0.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_2bds0.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.h,v 1.4.6.2 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bds0.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * specific defines for CCD's HFC 2BDS0
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c
--- linux-2.4.16/drivers/isdn/hisax/hfc_2bs0.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_2bs0.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.17.6.3 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bs0.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * specific routines for CCD's HFC 2BS0
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_2bs0.h linux/drivers/isdn/hisax/hfc_2bs0.h
--- linux-2.4.16/drivers/isdn/hisax/hfc_2bs0.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_2bs0.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.h,v 1.3.6.2 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bs0.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * specific defines for CCD's HFC 2BS0
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- linux-2.4.16/drivers/isdn/hisax/hfc_pci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_pci.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.34.6.8 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level driver for CCD´s hfc-pci based cards
  *
@@ -26,7 +26,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.34.6.8 $";
+static const char *hfcpci_revision = "$Revision: 1.1.4.1 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_pci.h linux/drivers/isdn/hisax/hfc_pci.h
--- linux-2.4.16/drivers/isdn/hisax/hfc_pci.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_pci.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.h,v 1.8.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfc_pci.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * specific defines for CCD's HFC 2BDS0 PCI chips
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c
--- linux-2.4.16/drivers/isdn/hisax/hfc_sx.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_sx.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_sx.c,v 1.9.6.3 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfc_sx.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * level driver for CCD´s hfc-s+/sp based cards
  *
@@ -20,7 +20,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcsx_revision = "$Revision: 1.9.6.3 $";
+static const char *hfcsx_revision = "$Revision: 1.1.4.1 $";
 
 /***************************************/
 /* IRQ-table for CCDs demo board       */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfc_sx.h linux/drivers/isdn/hisax/hfc_sx.h
--- linux-2.4.16/drivers/isdn/hisax/hfc_sx.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfc_sx.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfc_sx.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * specific defines for CCD's HFC 2BDS0 S+,SP chips
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c
--- linux-2.4.16/drivers/isdn/hisax/hfcscard.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hfcscard.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hfcscard.c,v 1.8.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfcscard.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  *
  * low level stuff for hfcs based cards (Teles3c, ACER P10)
  *
@@ -18,7 +18,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcs_revision = "$Revision: 1.8.6.2 $";
+static const char *hfcs_revision = "$Revision: 1.1.4.1 $";
 
 static void
 hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- linux-2.4.16/drivers/isdn/hisax/hisax.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hisax.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hisax.h,v 2.52.6.9 2001/09/23 22:24:48 kai Exp $
+/* $Id: hisax.h,v 1.1.4.2 2001/12/09 19:15:28 kai Exp $
  *
  * Basic declarations, defines and prototypes
  *
@@ -949,8 +949,6 @@
 #define  MON1_RX	2
 #define  MON0_TX	4
 #define  MON1_TX	8
-
-#define	 HISAX_MAX_CARDS	8
 
 #define  ISDN_CTYPE_16_0	1
 #define  ISDN_CTYPE_8_0		2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hisax_fcpcipnp.c linux/drivers/isdn/hisax/hisax_fcpcipnp.c
--- linux-2.4.16/drivers/isdn/hisax/hisax_fcpcipnp.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/isdn/hisax/hisax_fcpcipnp.c	Sun Dec  9 22:35:22 2001
@@ -0,0 +1,1001 @@
+/*
+ * Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *              2001 by Karsten Keil       <keil@isdn4linux.de>
+ * 
+ * based upon Karsten Keil's original avm_pci.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
+ *           SoHaNet Technology GmbH, Berlin
+ * for supporting the development of this driver
+ */
+
+
+/* TODO:
+ *
+ * o POWER PC
+ * o clean up debugging
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include "hisax_fcpcipnp.h"
+
+// debugging cruft
+#define __debug_variable debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");
+
+static struct pci_device_id fcpci_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1   , PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, (unsigned long) "Fritz!Card PCI" },
+	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, (unsigned long) "Fritz!Card PCI v2" },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, fcpci_ids);
+
+static struct isapnp_device_id fcpnp_ids[] __devinitdata = {
+	{ ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
+	  ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900), 
+	  (unsigned long) "Fritz!Card PnP" },
+	{ }
+};
+MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
+
+static int protocol = 2;       /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+// ----------------------------------------------------------------------
+
+#define  AVM_INDEX              0x04
+#define  AVM_DATA               0x10
+
+#define	 AVM_IDX_HDLC_1		0x00
+#define	 AVM_IDX_HDLC_2		0x01
+#define	 AVM_IDX_ISAC_FIFO	0x02
+#define	 AVM_IDX_ISAC_REG_LOW	0x04
+#define	 AVM_IDX_ISAC_REG_HIGH	0x06
+
+#define  AVM_STATUS0            0x02
+
+#define  AVM_STATUS0_IRQ_ISAC	0x01
+#define  AVM_STATUS0_IRQ_HDLC	0x02
+#define  AVM_STATUS0_IRQ_TIMER	0x04
+#define  AVM_STATUS0_IRQ_MASK	0x07
+
+#define  AVM_STATUS0_RESET	0x01
+#define  AVM_STATUS0_DIS_TIMER	0x02
+#define  AVM_STATUS0_RES_TIMER	0x04
+#define  AVM_STATUS0_ENA_IRQ	0x08
+#define  AVM_STATUS0_TESTBIT	0x10
+
+#define  AVM_STATUS1            0x03
+#define  AVM_STATUS1_ENA_IOM	0x80
+
+#define  HDLC_FIFO		0x0
+#define  HDLC_STATUS		0x4
+#define  HDLC_CTRL		0x4
+
+#define  HDLC_MODE_ITF_FLG	0x01
+#define  HDLC_MODE_TRANS	0x02
+#define  HDLC_MODE_CCR_7	0x04
+#define  HDLC_MODE_CCR_16	0x08
+#define  HDLC_MODE_TESTLOOP	0x80
+
+#define  HDLC_INT_XPR		0x80
+#define  HDLC_INT_XDU		0x40
+#define  HDLC_INT_RPR		0x20
+#define  HDLC_INT_MASK		0xE0
+
+#define  HDLC_STAT_RME		0x01
+#define  HDLC_STAT_RDO		0x10
+#define  HDLC_STAT_CRCVFRRAB	0x0E
+#define  HDLC_STAT_CRCVFR	0x06
+#define  HDLC_STAT_RML_MASK	0x3f00
+
+#define  HDLC_CMD_XRS		0x80
+#define  HDLC_CMD_XME		0x01
+#define  HDLC_CMD_RRS		0x20
+#define  HDLC_CMD_XML_MASK	0x3f00
+
+#define  AVM_HDLC_FIFO_1        0x10
+#define  AVM_HDLC_FIFO_2        0x18
+
+#define  AVM_HDLC_STATUS_1      0x14
+#define  AVM_HDLC_STATUS_2      0x1c
+
+#define  AVM_ISACSX_INDEX       0x04
+#define  AVM_ISACSX_DATA        0x08
+
+// ----------------------------------------------------------------------
+// Fritz!PCI
+
+static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned char idx = (offset > 0x2f) ? 
+		AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outb(idx, adapter->io + AVM_INDEX);
+	val = inb(adapter->io + AVM_DATA + (offset & 0xf));
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+	DBG(0x1000, " port %#x, value %#x",
+	    offset, val);
+	return val;
+}
+
+static void fcpci_write_isac(struct isac *isac, unsigned char offset,
+			     unsigned char value)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned char idx = (offset > 0x2f) ? 
+		AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
+	unsigned long flags;
+
+	DBG(0x1000, " port %#x, value %#x",
+	    offset, value);
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outb(idx, adapter->io + AVM_INDEX);
+	outb(value, adapter->io + AVM_DATA + (offset & 0xf));
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci_read_isac_fifo(struct isac *isac, unsigned char * data, 
+				 int size)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
+	insb(adapter->io + AVM_DATA, data, size);
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci_write_isac_fifo(struct isac *isac, unsigned char * data, 
+				  int size)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
+	outsb(adapter->io + AVM_DATA, data, size);
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr)
+{
+	u32 val;
+	int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outl(idx, adapter->io + AVM_INDEX);
+	val = inl(adapter->io + AVM_DATA + HDLC_STATUS);
+	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+	return val;
+}
+
+static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+
+	DBG(0x40, "hdlc %c wr%x ctrl %x",
+	    'A' + bcs->channel, which, bcs->ctrl.ctrl);
+
+	outl(idx, adapter->io + AVM_INDEX);
+	outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL);
+}
+
+static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	__fcpci_write_ctrl(bcs, which);
+	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+// ----------------------------------------------------------------------
+// Fritz!PCI v2
+
+static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outl(offset, adapter->io + AVM_ISACSX_INDEX);
+	val = inl(adapter->io + AVM_ISACSX_DATA);
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+	DBG(0x1000, " port %#x, value %#x",
+	    offset, val);
+
+	return val;
+}
+
+static void fcpci2_write_isac(struct isac *isac, unsigned char offset, 
+			      unsigned char value)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned long flags;
+
+	DBG(0x1000, " port %#x, value %#x",
+	    offset, value);
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outl(offset, adapter->io + AVM_ISACSX_INDEX);
+	outl(value, adapter->io + AVM_ISACSX_DATA);
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char * data, 
+				  int size)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outl(0, adapter->io + AVM_ISACSX_INDEX);
+	for (i = 0; i < size; i++)
+		data[i] = inl(adapter->io + AVM_ISACSX_DATA);
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char * data, 
+				   int size)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outl(0, adapter->io + AVM_ISACSX_INDEX);
+	for (i = 0; i < size; i++)
+		outl(data[i], adapter->io + AVM_ISACSX_DATA);
+ 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr)
+{
+	int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
+
+	return inl(adapter->io + offset);
+}
+
+static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
+
+	DBG(0x40, "hdlc %c wr%x ctrl %x",
+	    'A' + bcs->channel, which, bcs->ctrl.ctrl);
+
+	outl(bcs->ctrl.ctrl, adapter->io + offset);
+}
+
+// ----------------------------------------------------------------------
+// Fritz!PnP (ISAC access as for Fritz!PCI)
+
+static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr)
+{
+	unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	outb(idx, adapter->io + AVM_INDEX);
+	val = inb(adapter->io + AVM_DATA + HDLC_STATUS);
+	if (val & HDLC_INT_RPR)
+		val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8;
+	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+	return val;
+}
+
+static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+
+	DBG(0x40, "hdlc %c wr%x ctrl %x",
+	    'A' + bcs->channel, which, bcs->ctrl.ctrl);
+
+	outb(idx, adapter->io + AVM_INDEX);
+	if (which & 4)
+		outb(bcs->ctrl.sr.mode, 
+		     adapter->io + AVM_DATA + HDLC_STATUS + 2);
+	if (which & 2)
+		outb(bcs->ctrl.sr.xml, 
+		     adapter->io + AVM_DATA + HDLC_STATUS + 1);
+	if (which & 1)
+		outb(bcs->ctrl.sr.cmd,
+		     adapter->io + AVM_DATA + HDLC_STATUS + 0);
+}
+
+static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hw_lock, flags);
+	__fcpnp_write_ctrl(bcs, which);
+	spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+// ----------------------------------------------------------------------
+
+static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg)
+{
+	struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
+
+	DBG(2, "pr %#x", pr);
+	ifc->l1l2(ifc, pr, arg);
+}
+
+static void hdlc_fill_fifo(struct fritz_bcs *bcs)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	struct sk_buff *skb = bcs->tx_skb;
+	int count;
+	int fifo_size = 32;
+	unsigned long flags;
+	unsigned char *p;
+
+	DBG(0x40, "hdlc_fill_fifo");
+
+	if (!skb)
+		BUG();
+
+	if (skb->len == 0)
+		BUG();
+
+	bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;
+	if (bcs->tx_skb->len > fifo_size) {
+		count = fifo_size;
+	} else {
+		count = bcs->tx_skb->len;
+		if (bcs->mode != L1_MODE_TRANS)
+			bcs->ctrl.sr.cmd |= HDLC_CMD_XME;
+	}
+	DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len);
+	p = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt += count;
+	bcs->ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
+
+	switch (adapter->type) {
+	case AVM_FRITZ_PCI:
+		spin_lock_irqsave(&adapter->hw_lock, flags);
+		// sets the correct AVM_INDEX, too
+		__fcpci_write_ctrl(bcs, 3);
+		outsl(adapter->io + AVM_DATA + HDLC_FIFO,
+		      p, (count + 3) / 4);
+		spin_unlock_irqrestore(&adapter->hw_lock, flags);
+		break;
+	case AVM_FRITZ_PCIV2:
+		fcpci2_write_ctrl(bcs, 3);
+		outsl(adapter->io + 
+		      (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
+		      p, (count + 3) / 4);
+		break;
+	case AVM_FRITZ_PNP:
+		spin_lock_irqsave(&adapter->hw_lock, flags);
+		// sets the correct AVM_INDEX, too
+		__fcpnp_write_ctrl(bcs, 3);
+		outsb(adapter->io + AVM_DATA, p, count);
+		spin_unlock_irqrestore(&adapter->hw_lock, flags);
+		break;
+	}
+}
+
+static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	unsigned char *p;
+	unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+
+	DBG(0x10, "hdlc_empty_fifo %d", count);
+	if (bcs->rcvidx + count > HSCX_BUFMAX) {
+		DBG(0x10, "hdlc_empty_fifo: incoming packet too large");
+		return;
+	}
+	p = bcs->rcvbuf + bcs->rcvidx;
+	bcs->rcvidx += count;
+	switch (adapter->type) {
+	case AVM_FRITZ_PCI:
+		spin_lock(&adapter->hw_lock);
+		outl(idx, adapter->io + AVM_INDEX);
+		insl(adapter->io + AVM_DATA + HDLC_FIFO, 
+		     p, (count + 3) / 4);
+		spin_unlock(&adapter->hw_lock);
+		break;
+	case AVM_FRITZ_PCIV2:
+		insl(adapter->io + 
+		     (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
+		     p, (count + 3) / 4);
+		break;
+	case AVM_FRITZ_PNP:
+		spin_lock(&adapter->hw_lock);
+		outb(idx, adapter->io + AVM_INDEX);
+		insb(adapter->io + AVM_DATA, p, count);
+		spin_unlock(&adapter->hw_lock);
+		break;
+	}
+}
+
+static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	struct sk_buff *skb;
+	int len;
+
+	if (stat & HDLC_STAT_RDO) {
+		DBG(0x10, "RDO");
+		bcs->ctrl.sr.xml = 0;
+		bcs->ctrl.sr.cmd |= HDLC_CMD_RRS;
+		adapter->write_ctrl(bcs, 1);
+		bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
+		adapter->write_ctrl(bcs, 1);
+		bcs->rcvidx = 0;
+		return;
+	}
+
+	len = (stat & HDLC_STAT_RML_MASK) >> 8;
+	if (len == 0)
+		len = 32;
+
+	hdlc_empty_fifo(bcs, len);
+
+	if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
+		if (((stat & HDLC_STAT_CRCVFRRAB)== HDLC_STAT_CRCVFR) ||
+		    (bcs->mode == L1_MODE_TRANS)) {
+			skb = dev_alloc_skb(bcs->rcvidx);
+			if (!skb) {
+				printk(KERN_WARNING "HDLC: receive out of memory\n");
+			} else {
+				memcpy(skb_put(skb, bcs->rcvidx), bcs->rcvbuf,
+				       bcs->rcvidx);
+				DBG_SKB(1, skb);
+				B_L1L2(bcs, PH_DATA | INDICATION, skb);
+			}
+			bcs->rcvidx = 0;
+		} else {
+			DBG(0x10, "ch%d invalid frame %#x",
+			    bcs->channel, stat);
+			bcs->rcvidx = 0;
+		}
+	}
+}
+
+static inline void hdlc_xdu_irq(struct fritz_bcs *bcs)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+
+	/* Here we lost an TX interrupt, so
+	 * restart transmitting the whole frame.
+	 */
+	bcs->ctrl.sr.xml = 0;
+	bcs->ctrl.sr.cmd |= HDLC_CMD_XRS;
+	adapter->write_ctrl(bcs, 1);
+	bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+	adapter->write_ctrl(bcs, 1);
+
+	if (!bcs->tx_skb) {
+		DBG(0x10, "XDU without skb");
+		return;
+	}
+	skb_push(bcs->tx_skb, bcs->tx_cnt);
+	bcs->tx_cnt = 0;
+}
+
+static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
+{
+	struct sk_buff *skb;
+
+	skb = bcs->tx_skb;
+	if (!skb)
+		return;
+
+	if (skb->len) {
+		hdlc_fill_fifo(bcs);
+		return;
+	}
+	bcs->tx_cnt = 0;
+	bcs->tx_skb = NULL;
+	B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+	dev_kfree_skb_irq(skb);
+}
+
+static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat)
+{
+	DBG(0x10, "ch%d stat %#x", bcs->channel, stat);
+	if (stat & HDLC_INT_RPR) {
+		DBG(0x10, "RPR");
+		hdlc_rpr_irq(bcs, stat);
+	}
+	if (stat & HDLC_INT_XDU) {
+		DBG(0x10, "XDU");
+		hdlc_xdu_irq(bcs);
+	}
+	if (stat & HDLC_INT_XPR) {
+		DBG(0x10, "XPR");
+		hdlc_xpr_irq(bcs);
+	}
+}
+
+static inline void hdlc_irq(struct fritz_adapter *adapter)
+{
+	int nr;
+	u32 stat;
+
+	for (nr = 0; nr < 2; nr++) {
+		stat = adapter->read_hdlc_status(adapter, nr);
+		DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat);
+		if (stat & HDLC_INT_MASK)
+			hdlc_irq_one(&adapter->bcs[nr], stat);
+	}
+}
+
+static void modehdlc(struct fritz_bcs *bcs, int mode)
+{
+	struct fritz_adapter *adapter = bcs->adapter;
+	
+	DBG(0x40, "hdlc %c mode %d --> %d",
+	    'A' + bcs->channel, bcs->mode, mode);
+
+	if (bcs->mode == mode)
+		return;
+
+	bcs->ctrl.ctrl = 0;
+	bcs->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+	switch (mode) {
+	case L1_MODE_NULL:
+		bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+		adapter->write_ctrl(bcs, 5);
+		break;
+	case L1_MODE_TRANS:
+		bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+		adapter->write_ctrl(bcs, 5);
+		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
+		adapter->write_ctrl(bcs, 1);
+		bcs->ctrl.sr.cmd = 0;
+		break;
+	case L1_MODE_HDLC:
+		bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+		adapter->write_ctrl(bcs, 5);
+		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
+		adapter->write_ctrl(bcs, 1);
+		bcs->ctrl.sr.cmd = 0;
+		break;
+	}
+	bcs->mode = mode;
+}
+
+static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
+{
+	struct fritz_bcs *bcs = ifc->priv;
+	struct sk_buff *skb = arg;
+	int mode;
+
+	DBG(0x10, "pr %#x", pr);
+
+	switch (pr) {
+	case PH_DATA | REQUEST:
+		if (bcs->tx_skb)
+			BUG();
+		
+		bcs->tx_skb = skb;
+		DBG_SKB(1, skb);
+		hdlc_fill_fifo(bcs);
+		break;
+	case PH_ACTIVATE | REQUEST:
+		mode = (int) arg;
+		DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
+		modehdlc(bcs, mode);
+		B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
+		break;
+	case PH_DEACTIVATE | REQUEST:
+		DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
+		modehdlc(bcs, L1_MODE_NULL);
+		B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
+		break;
+	}
+}
+
+// ----------------------------------------------------------------------
+
+static void fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
+{
+	struct fritz_adapter *adapter = dev;
+	unsigned char val;
+
+	val = inb(adapter->io + AVM_STATUS0);
+	if (!(val & AVM_STATUS0_IRQ_MASK))
+		/* hopefully a shared  IRQ reqest */
+		return;
+	DBG(2, "STATUS0 %#x", val);
+	if (val & AVM_STATUS0_IRQ_ISAC)
+		isacsx_irq(&adapter->isac);
+
+	if (val & AVM_STATUS0_IRQ_HDLC)
+		hdlc_irq(adapter);
+}
+
+static void fcpci_irq(int intno, void *dev, struct pt_regs *regs)
+{
+	struct fritz_adapter *adapter = dev;
+	unsigned char sval;
+
+	sval = inb(adapter->io + 2);
+	if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)
+		/* possibly a shared  IRQ reqest */
+		return;
+	DBG(2, "sval %#x", sval);
+	if (!(sval & AVM_STATUS0_IRQ_ISAC))
+		isac_irq(&adapter->isac);
+
+	if (!(sval & AVM_STATUS0_IRQ_HDLC))
+		hdlc_irq(adapter);
+}
+
+// ----------------------------------------------------------------------
+
+static inline void fcpci2_init(struct fritz_adapter *adapter)
+{
+	outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0);
+	outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
+
+}
+
+static inline void fcpci_init(struct fritz_adapter *adapter)
+{
+	outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | 
+	     AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
+
+	outb(AVM_STATUS1_ENA_IOM | adapter->irq, 
+	     adapter->io + AVM_STATUS1);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(50*HZ / 1000); /* Timeout 50ms */
+}
+
+// ----------------------------------------------------------------------
+
+static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)
+{
+	u32 val = 0;
+	int retval;
+
+	DBG(1,"");
+
+	isac_init(&adapter->isac); // FIXME is this okay now
+
+	retval = -EBUSY;
+	if (!request_region(adapter->io, 32, "fcpcipnp"))
+		goto err;
+
+	switch (adapter->type) {
+	case AVM_FRITZ_PCIV2:
+		retval = request_irq(adapter->irq, fcpci2_irq, SA_SHIRQ, 
+				     "fcpcipnp", adapter);
+		break;
+	case AVM_FRITZ_PCI:
+		retval = request_irq(adapter->irq, fcpci_irq, SA_SHIRQ,
+				     "fcpcipnp", adapter);
+		break;
+	case AVM_FRITZ_PNP:
+		retval = request_irq(adapter->irq, fcpci_irq, 0,
+				     "fcpcipnp", adapter);
+		break;
+	}
+	if (retval)
+		goto err_region;
+
+	switch (adapter->type) {
+	case AVM_FRITZ_PCIV2:
+	case AVM_FRITZ_PCI:
+		val = inl(adapter->io);
+		break;
+	case AVM_FRITZ_PNP:
+		val = inb(adapter->io);
+		val |= inb(adapter->io + 1) << 8;
+		break;
+	}
+
+	DBG(1, "stat %#x Class %X Rev %d",
+	    val, val & 0xff, (val>>8) & 0xff);
+
+	spin_lock_init(&adapter->hw_lock);
+	adapter->isac.priv = adapter;
+	switch (adapter->type) {
+	case AVM_FRITZ_PCIV2:
+		adapter->isac.read_isac       = &fcpci2_read_isac;;
+		adapter->isac.write_isac      = &fcpci2_write_isac;
+		adapter->isac.read_isac_fifo  = &fcpci2_read_isac_fifo;
+		adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo;
+
+		adapter->read_hdlc_status     = &fcpci2_read_hdlc_status;
+		adapter->write_ctrl           = &fcpci2_write_ctrl;
+		break;
+	case AVM_FRITZ_PCI:
+		adapter->isac.read_isac       = &fcpci_read_isac;;
+		adapter->isac.write_isac      = &fcpci_write_isac;
+		adapter->isac.read_isac_fifo  = &fcpci_read_isac_fifo;
+		adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
+
+		adapter->read_hdlc_status     = &fcpci_read_hdlc_status;
+		adapter->write_ctrl           = &fcpci_write_ctrl;
+		break;
+	case AVM_FRITZ_PNP:
+		adapter->isac.read_isac       = &fcpci_read_isac;;
+		adapter->isac.write_isac      = &fcpci_write_isac;
+		adapter->isac.read_isac_fifo  = &fcpci_read_isac_fifo;
+		adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
+
+		adapter->read_hdlc_status     = &fcpnp_read_hdlc_status;
+		adapter->write_ctrl           = &fcpnp_write_ctrl;
+		break;
+	}
+
+	// Reset
+	outb(0, adapter->io + AVM_STATUS0);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(50 * HZ / 1000); // 50 msec
+	outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(50 * HZ / 1000); // 50 msec
+	outb(0, adapter->io + AVM_STATUS0);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(10 * HZ / 1000); // 10 msec
+
+	switch (adapter->type) {
+	case AVM_FRITZ_PCIV2:
+		fcpci2_init(adapter);
+		isacsx_setup(&adapter->isac);
+		break;
+	case AVM_FRITZ_PCI:
+	case AVM_FRITZ_PNP:
+		fcpci_init(adapter);
+		isac_setup(&adapter->isac);
+		break;
+	}
+	val = adapter->read_hdlc_status(adapter, 0);
+	DBG(0x20, "HDLC A STA %x", val);
+	val = adapter->read_hdlc_status(adapter, 1);
+	DBG(0x20, "HDLC B STA %x", val);
+
+	adapter->bcs[0].mode = -1;
+	adapter->bcs[1].mode = -1;
+	modehdlc(&adapter->bcs[0], L1_MODE_NULL);
+	modehdlc(&adapter->bcs[1], L1_MODE_NULL);
+
+	return 0;
+
+ err_region:
+	release_region(adapter->io, 32);
+ err:
+	return retval;
+}
+
+static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)
+{
+	DBG(1,"");
+
+	outb(0, adapter->io + AVM_STATUS0);
+	free_irq(adapter->irq, adapter);
+	release_region(adapter->io, 32);
+}
+
+// ----------------------------------------------------------------------
+
+static struct fritz_adapter * __devinit 
+new_adapter(struct pci_dev *pdev)
+{
+	struct fritz_adapter *adapter;
+	struct hisax_b_if *b_if[2];
+	int i;
+
+	adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
+	if (!adapter)
+		return NULL;
+
+	memset(adapter, 0, sizeof(struct fritz_adapter));
+
+	SET_MODULE_OWNER(&adapter->isac.hisax_d_if);
+	adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
+	adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
+	
+	for (i = 0; i < 2; i++) {
+		adapter->bcs[i].adapter = adapter;
+		adapter->bcs[i].channel = i;
+		adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
+		adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;
+	}
+
+	pci_set_drvdata(pdev, adapter);
+
+	for (i = 0; i < 2; i++)
+		b_if[i] = &adapter->bcs[i].b_if;
+
+	hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp", protocol);
+
+	return adapter;
+}
+
+static void delete_adapter(struct fritz_adapter *adapter)
+{
+	hisax_unregister(&adapter->isac.hisax_d_if);
+	kfree(adapter);
+}
+
+static int __devinit fcpci_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
+{
+	struct fritz_adapter *adapter;
+	int retval;
+
+	retval = -ENOMEM;
+	adapter = new_adapter(pdev);
+	if (!adapter)
+		goto err;
+
+	if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) 
+		adapter->type = AVM_FRITZ_PCIV2;
+	else
+		adapter->type = AVM_FRITZ_PCI;
+
+	retval = pci_enable_device(pdev);
+	if (retval)
+		goto err_free;
+
+	adapter->io = pci_resource_start(pdev, 1);
+	adapter->irq = pdev->irq;
+
+	printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
+	       (char *) ent->driver_data, pdev->slot_name);
+
+	retval = fcpcipnp_setup(adapter);
+	if (retval)
+		goto err_free;
+
+	return 0;
+	
+ err_free:
+	delete_adapter(adapter);
+ err:
+	return retval;
+}
+
+static int __devinit fcpnp_probe(struct pci_dev *pdev,
+				 const struct isapnp_device_id *ent)
+{
+	struct fritz_adapter *adapter;
+	int retval;
+
+	retval = -ENOMEM;
+	adapter = new_adapter(pdev);
+	if (!adapter)
+		goto err;
+
+	adapter->type = AVM_FRITZ_PNP;
+
+	pdev->prepare(pdev);
+	pdev->deactivate(pdev); // why?
+	pdev->activate(pdev);
+	adapter->io = pdev->resource[0].start;
+	adapter->irq = pdev->irq_resource[0].start;
+
+	printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",
+	       (char *) ent->driver_data, adapter->io, adapter->irq);
+
+	retval = fcpcipnp_setup(adapter);
+	if (retval)
+		goto err_free;
+
+	return 0;
+	
+ err_free:
+	delete_adapter(adapter);
+ err:
+	return retval;
+}
+
+static void __devexit fcpci_remove(struct pci_dev *pdev)
+{
+	struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+	fcpcipnp_release(adapter);
+	pci_disable_device(pdev);
+	delete_adapter(adapter);
+}
+
+static void __devexit fcpnp_remove(struct pci_dev *pdev)
+{
+	struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+	fcpcipnp_release(adapter);
+	pdev->deactivate(pdev);
+	delete_adapter(adapter);
+}
+
+static struct pci_driver fcpci_driver = {
+	name:     "fcpci",
+	probe:    fcpci_probe,
+	remove:   __devexit_p(fcpci_remove),
+	id_table: fcpci_ids,
+};
+
+static struct isapnp_driver fcpnp_driver = {
+	name:     "fcpnp",
+	probe:    fcpnp_probe,
+	remove:   __devexit_p(fcpnp_remove),
+	id_table: fcpnp_ids,
+};
+
+static int __init hisax_fcpcipnp_init(void)
+{
+	int retval, pci_nr_found;
+
+	printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
+
+	retval = pci_register_driver(&fcpci_driver);
+	if (retval < 0)
+		goto out;
+	pci_nr_found = retval;
+
+	retval = isapnp_register_driver(&fcpnp_driver);
+	if (retval < 0)
+		goto out_unregister_pci;
+
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+	if (pci_nr_found + retval == 0) {
+		retval = -ENODEV;
+		goto out_unregister_isapnp;
+	}
+#endif
+	return 0;
+
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+ out_unregister_isapnp:
+	isapnp_unregister_driver(&fcpnp_driver);
+#endif
+ out_unregister_pci:
+	pci_unregister_driver(&fcpci_driver);
+ out:
+	return retval;
+}
+
+static void __exit hisax_fcpcipnp_exit(void)
+{
+	isapnp_unregister_driver(&fcpnp_driver);
+	pci_unregister_driver(&fcpci_driver);
+}
+
+module_init(hisax_fcpcipnp_init);
+module_exit(hisax_fcpcipnp_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hisax_fcpcipnp.h linux/drivers/isdn/hisax/hisax_fcpcipnp.h
--- linux-2.4.16/drivers/isdn/hisax/hisax_fcpcipnp.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/isdn/hisax/hisax_fcpcipnp.h	Tue Dec  4 19:28:22 2001
@@ -0,0 +1,57 @@
+#include "hisax_if.h"
+#include "hisax_isac.h"
+#include <linux/pci.h>
+
+#define HSCX_BUFMAX	4096
+
+enum {
+	AVM_FRITZ_PCI,
+	AVM_FRITZ_PNP,
+	AVM_FRITZ_PCIV2,
+};
+
+struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+	u_char fill __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char cmd  __attribute__((packed));
+#else
+	u_char cmd  __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char fill __attribute__((packed));
+#endif
+};
+
+struct fritz_bcs {
+	struct hisax_b_if b_if;
+	struct fritz_adapter *adapter;
+	int mode;
+	int channel;
+
+	union {
+		u_int ctrl;
+		struct hdlc_stat_reg sr;
+	} ctrl;
+	u_int stat;
+	int rcvidx;
+	u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
+
+	int tx_cnt;		    /* B-Channel transmit counter */
+	struct sk_buff *tx_skb;     /* B-Channel transmit Buffer */
+};
+
+struct fritz_adapter {
+	int type;
+	spinlock_t hw_lock;
+	unsigned int io;
+	unsigned int irq;
+	struct isac isac;
+
+	struct fritz_bcs bcs[2];
+
+	u32  (*read_hdlc_status) (struct fritz_adapter *adapter, int nr);
+	void (*write_ctrl) (struct fritz_bcs *bcs, int which);
+};
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hisax_isac.c linux/drivers/isdn/hisax/hisax_isac.c
--- linux-2.4.16/drivers/isdn/hisax/hisax_isac.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/isdn/hisax/hisax_isac.c	Thu Dec  6 19:04:52 2001
@@ -0,0 +1,896 @@
+/*
+ * Driver for ISAC-S and ISAC-SX 
+ * ISDN Subscriber Access Controller for Terminals
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *              2001 by Karsten Keil       <keil@isdn4linux.de>
+ * 
+ * based upon Karsten Keil's original isac.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
+ *           SoHaNet Technology GmbH, Berlin
+ * for supporting the development of this driver
+ */
+
+/* TODO:
+ * specifically handle level vs edge triggered?
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include "hisax_isac.h"
+
+// debugging cruft
+
+#define __debug_variable debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 1;
+MODULE_PARM(debug, "i");
+
+static char *ISACVer[] = {
+  "2086/2186 V1.1", 
+  "2085 B1", 
+  "2085 B2",
+  "2085 V2.3"
+};
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
+
+#define DBG_WARN      0x0001
+#define DBG_IRQ       0x0002
+#define DBG_L1M       0x0004
+#define DBG_PR        0x0008
+#define DBG_RFIFO     0x0100
+#define DBG_RPACKET   0x0200
+#define DBG_XFIFO     0x1000
+#define DBG_XPACKET   0x2000
+
+// we need to distinguish ISAC-S and ISAC-SX
+#define TYPE_ISAC        0x00
+#define TYPE_ISACSX      0x01
+
+// registers etc.
+#define ISAC_MASK        0x20
+#define ISAC_ISTA        0x20
+#define ISAC_ISTA_EXI    0x01
+#define ISAC_ISTA_SIN    0x02
+#define ISAC_ISTA_CISQ   0x04
+#define ISAC_ISTA_XPR    0x10
+#define ISAC_ISTA_RSC    0x20
+#define ISAC_ISTA_RPF    0x40
+#define ISAC_ISTA_RME    0x80
+
+#define ISAC_STAR        0x21
+#define ISAC_CMDR        0x21
+#define ISAC_CMDR_XRES   0x01
+#define ISAC_CMDR_XME    0x02
+#define ISAC_CMDR_XTF    0x08
+#define ISAC_CMDR_RRES   0x40
+#define ISAC_CMDR_RMC    0x80
+
+#define ISAC_EXIR        0x24
+#define ISAC_EXIR_MOS    0x04
+#define ISAC_EXIR_XDU    0x40
+#define ISAC_EXIR_XMR    0x80
+
+#define ISAC_ADF2        0x39
+#define ISAC_SPCR        0x30
+#define ISAC_ADF1        0x38
+
+#define ISAC_CIR0        0x31
+#define ISAC_CIX0        0x31
+#define ISAC_CIR0_CIC0   0x02
+#define ISAC_CIR0_CIC1   0x01
+
+#define ISAC_CIR1        0x33
+#define ISAC_CIX1        0x33
+#define ISAC_STCR        0x37
+#define ISAC_MODE        0x22
+
+#define ISAC_RSTA        0x27
+#define ISAC_RSTA_RDO    0x40
+#define ISAC_RSTA_CRC    0x20
+#define ISAC_RSTA_RAB    0x10
+
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_RBCH_XAC 0x80
+
+#define ISAC_CMD_TIM    0x0
+#define ISAC_CMD_RES    0x1
+#define ISAC_CMD_SSP    0x2
+#define ISAC_CMD_SCP    0x3
+#define ISAC_CMD_AR8    0x8
+#define ISAC_CMD_AR10   0x9
+#define ISAC_CMD_ARL    0xa
+#define ISAC_CMD_DI     0xf
+
+#define ISACSX_MASK       0x60
+#define ISACSX_ISTA       0x60
+#define ISACSX_ISTA_ICD   0x01
+#define ISACSX_ISTA_CIC   0x10
+
+#define ISACSX_MASKD      0x20
+#define ISACSX_ISTAD      0x20
+#define ISACSX_ISTAD_XDU  0x04
+#define ISACSX_ISTAD_XMR  0x08
+#define ISACSX_ISTAD_XPR  0x10
+#define ISACSX_ISTAD_RFO  0x20
+#define ISACSX_ISTAD_RPF  0x40
+#define ISACSX_ISTAD_RME  0x80
+
+#define ISACSX_CMDRD      0x21
+#define ISACSX_CMDRD_XRES 0x01
+#define ISACSX_CMDRD_XME  0x02
+#define ISACSX_CMDRD_XTF  0x08
+#define ISACSX_CMDRD_RRES 0x40
+#define ISACSX_CMDRD_RMC  0x80
+
+#define ISACSX_MODED      0x22
+
+#define ISACSX_RBCLD      0x26
+
+#define ISACSX_RSTAD      0x28
+#define ISACSX_RSTAD_RAB  0x10
+#define ISACSX_RSTAD_CRC  0x20
+#define ISACSX_RSTAD_RDO  0x40
+#define ISACSX_RSTAD_VFR  0x80
+
+#define ISACSX_CIR0       0x2e
+#define ISACSX_CIR0_CIC0  0x08
+#define ISACSX_CIX0       0x2e
+
+#define ISACSX_TR_CONF0   0x30
+
+#define ISACSX_TR_CONF2   0x32
+
+static struct Fsm l1fsm;
+
+enum {
+	ST_L1_RESET,
+	ST_L1_F3_PDOWN,
+	ST_L1_F3_PUP,
+	ST_L1_F3_PEND_DEACT,
+	ST_L1_F4,
+	ST_L1_F5,
+	ST_L1_F6,
+	ST_L1_F7,
+	ST_L1_F8,
+};
+
+#define L1_STATE_COUNT (ST_L1_F8+1)
+
+static char *strL1State[] =
+{
+	"ST_L1_RESET",
+	"ST_L1_F3_PDOWN",
+	"ST_L1_F3_PUP",
+	"ST_L1_F3_PEND_DEACT",
+	"ST_L1_F4",
+	"ST_L1_F5",
+	"ST_L1_F6",
+	"ST_L1_F7",
+	"ST_L1_F8",
+};
+
+enum {
+	EV_PH_DR,           // 0000
+	EV_PH_RES,          // 0001
+	EV_PH_TMA,          // 0010
+	EV_PH_SLD,          // 0011
+	EV_PH_RSY,          // 0100
+	EV_PH_DR6,          // 0101
+	EV_PH_EI,           // 0110
+	EV_PH_PU,           // 0111
+	EV_PH_AR,           // 1000
+	EV_PH_9,            // 1001
+	EV_PH_ARL,          // 1010
+	EV_PH_CVR,          // 1011
+	EV_PH_AI8,          // 1100
+	EV_PH_AI10,         // 1101
+	EV_PH_AIL,          // 1110
+	EV_PH_DC,           // 1111
+	EV_PH_ACTIVATE_REQ,
+	EV_PH_DEACTIVATE_REQ,
+	EV_TIMER3,
+};
+
+#define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+static char *strL1Event[] =
+{
+	"EV_PH_DR",           // 0000
+	"EV_PH_RES",          // 0001
+	"EV_PH_TMA",          // 0010
+	"EV_PH_SLD",          // 0011
+	"EV_PH_RSY",          // 0100
+	"EV_PH_DR6",          // 0101
+	"EV_PH_EI",           // 0110
+	"EV_PH_PU",           // 0111
+	"EV_PH_AR",           // 1000
+	"EV_PH_9",            // 1001
+	"EV_PH_ARL",          // 1010
+	"EV_PH_CVR",          // 1011
+	"EV_PH_AI8",          // 1100
+	"EV_PH_AI10",         // 1101
+	"EV_PH_AIL",          // 1110
+	"EV_PH_DC",           // 1111
+	"EV_PH_ACTIVATE_REQ",
+	"EV_PH_DEACTIVATE_REQ",
+	"EV_TIMER3",
+};
+
+static inline void D_L1L2(struct isac *isac, int pr, void *arg)
+{
+	struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
+
+	DBG(DBG_PR, "pr %#x", pr);
+	ifc->l1l2(ifc, pr, arg);
+}
+
+static void ph_command(struct isac *isac, unsigned int command)
+{
+	DBG(DBG_L1M, "ph_command %#x", command);
+	switch (isac->type) {
+	case TYPE_ISAC:
+		isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
+		break;
+	case TYPE_ISACSX:
+		isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
+		break;
+	}
+}
+
+// ----------------------------------------------------------------------
+
+static void l1_di(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_RESET);
+	ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_RESET);
+	D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+	ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L1_F3_PDOWN);
+}
+
+static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
+	D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+	ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
+	ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L1_F4);
+}
+
+static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L1_F5);
+}
+
+static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L1_F6);
+}
+
+static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_F6);
+	D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmDelTimer(&isac->timer, 0);
+	FsmChangeState(fi, ST_L1_F7);
+	ph_command(isac, ISAC_CMD_AR8);
+	D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
+}
+
+static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L1_F8);
+}
+
+static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_F8);
+	D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+static void l1_ar8(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+	ph_command(isac, ISAC_CMD_AR8);
+}
+
+static void l1_timer3(struct FsmInst *fi, int event, void *arg)
+{
+	struct isac *isac = fi->userdata;
+
+	ph_command(isac, ISAC_CMD_DI);
+	D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+// state machines according to data sheet PSB 2186 / 3186
+
+static struct FsmNode L1FnList[] __initdata =
+{
+	{ST_L1_RESET,         EV_PH_RES,            l1_di},
+	{ST_L1_RESET,         EV_PH_EI,             l1_di},
+	{ST_L1_RESET,         EV_PH_DC,             l1_go_f3pdown},
+	{ST_L1_RESET,         EV_PH_AR,             l1_go_f6},
+	{ST_L1_RESET,         EV_PH_AI8,            l1_go_f7_act_ind},
+
+	{ST_L1_F3_PDOWN,      EV_PH_RES,            l1_di},
+	{ST_L1_F3_PDOWN,      EV_PH_EI,             l1_di},
+	{ST_L1_F3_PDOWN,      EV_PH_AR,             l1_go_f6},
+	{ST_L1_F3_PDOWN,      EV_PH_RSY,            l1_go_f5},
+	{ST_L1_F3_PDOWN,      EV_PH_PU,             l1_go_f4},
+	{ST_L1_F3_PDOWN,      EV_PH_AI8,            l1_go_f7_act_ind},
+	{ST_L1_F3_PDOWN,      EV_PH_ACTIVATE_REQ,   l1_ar8},
+	{ST_L1_F3_PDOWN,      EV_TIMER3,            l1_timer3},
+	
+	{ST_L1_F3_PEND_DEACT, EV_PH_RES,            l1_di},
+	{ST_L1_F3_PEND_DEACT, EV_PH_EI,             l1_di},
+	{ST_L1_F3_PEND_DEACT, EV_PH_DC,             l1_go_f3pdown},
+	{ST_L1_F3_PEND_DEACT, EV_PH_RSY,            l1_go_f5},
+	{ST_L1_F3_PEND_DEACT, EV_PH_AR,             l1_go_f6},
+	{ST_L1_F3_PEND_DEACT, EV_PH_AI8,            l1_go_f7_act_ind},
+
+	{ST_L1_F4,            EV_PH_RES,            l1_di},
+	{ST_L1_F4,            EV_PH_EI,             l1_di},
+	{ST_L1_F4,            EV_PH_RSY,            l1_go_f5},
+	{ST_L1_F4,            EV_PH_AI8,            l1_go_f7_act_ind},
+	{ST_L1_F4,            EV_TIMER3,            l1_timer3},
+	{ST_L1_F4,            EV_PH_DC,             l1_go_f3pdown},
+
+	{ST_L1_F5,            EV_PH_RES,            l1_di},
+	{ST_L1_F5,            EV_PH_EI,             l1_di},
+	{ST_L1_F5,            EV_PH_AR,             l1_go_f6},
+	{ST_L1_F5,            EV_PH_AI8,            l1_go_f7_act_ind},
+	{ST_L1_F5,            EV_TIMER3,            l1_timer3},
+	{ST_L1_F5,            EV_PH_DR,             l1_go_f3pend},
+	{ST_L1_F5,            EV_PH_DC,             l1_go_f3pdown},
+
+	{ST_L1_F6,            EV_PH_RES,            l1_di},
+	{ST_L1_F6,            EV_PH_EI,             l1_di},
+	{ST_L1_F6,            EV_PH_RSY,            l1_go_f8},
+	{ST_L1_F6,            EV_PH_AI8,            l1_go_f7_act_ind},
+	{ST_L1_F6,            EV_PH_DR6,            l1_go_f3pend},
+	{ST_L1_F6,            EV_TIMER3,            l1_timer3},
+	{ST_L1_F6,            EV_PH_DC,             l1_go_f3pdown},
+
+	{ST_L1_F7,            EV_PH_RES,            l1_di_deact_ind},
+	{ST_L1_F7,            EV_PH_EI,             l1_di_deact_ind},
+	{ST_L1_F7,            EV_PH_AR,             l1_go_f6_deact_ind},
+	{ST_L1_F7,            EV_PH_RSY,            l1_go_f8_deact_ind},
+	{ST_L1_F7,            EV_PH_DR,             l1_go_f3pend_deact_ind},
+
+	{ST_L1_F8,            EV_PH_RES,            l1_di},
+	{ST_L1_F8,            EV_PH_EI,             l1_di},
+	{ST_L1_F8,            EV_PH_AR,             l1_go_f6},
+	{ST_L1_F8,            EV_PH_DR,             l1_go_f3pend},
+	{ST_L1_F8,            EV_PH_AI8,            l1_go_f7_act_ind},
+	{ST_L1_F8,            EV_TIMER3,            l1_timer3},
+	{ST_L1_F8,            EV_PH_DC,             l1_go_f3pdown},
+};
+
+static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	va_list args;
+	char buf[256];
+	
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	DBG(DBG_L1M, "%s", buf);
+	va_end(args);
+}
+
+static void isac_version(struct isac *cs)
+{
+	int val;
+
+	val = cs->read_isac(cs, ISAC_RBCH);
+	DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
+}
+
+static void isac_empty_fifo(struct isac *isac, int count)
+{
+	// this also works for isacsx, since
+	// CMDR(D) register works the same
+	u_char *ptr;
+
+	DBG(DBG_IRQ, "count %d", count);
+
+	if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
+		isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
+		isac->rcvidx = 0;
+		return;
+	}
+	ptr = isac->rcvbuf + isac->rcvidx;
+	isac->rcvidx += count;
+	isac->read_isac_fifo(isac, ptr, count);
+	isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
+	DBG_PACKET(DBG_RFIFO, ptr, count);
+}
+
+static void isac_fill_fifo(struct isac *isac)
+{
+	// this also works for isacsx, since
+	// CMDR(D) register works the same
+
+	int count;
+	unsigned char cmd;
+	u_char *ptr;
+
+	if (!isac->tx_skb)
+		BUG();
+
+	count = isac->tx_skb->len;
+	if (count <= 0)
+		BUG();
+
+	DBG(DBG_IRQ, "count %d", count);
+
+	if (count > 0x20) {
+		count = 0x20;
+		cmd = ISAC_CMDR_XTF;
+	} else {
+		cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
+	}
+
+	ptr = isac->tx_skb->data;
+	skb_pull(isac->tx_skb, count);
+	isac->tx_cnt += count;
+	DBG_PACKET(DBG_XFIFO, ptr, count);
+	isac->write_isac_fifo(isac, ptr, count);
+	isac->write_isac(isac, ISAC_CMDR, cmd);
+}
+
+static void isac_retransmit(struct isac *isac)
+{
+	if (!isac->tx_skb) {
+		DBG(DBG_WARN, "no skb");
+		return;
+	}
+	skb_push(isac->tx_skb, isac->tx_cnt);
+	isac->tx_cnt = 0;
+}
+
+
+static inline void isac_cisq_interrupt(struct isac *isac)
+{
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISAC_CIR0);
+	DBG(DBG_IRQ, "CIR0 %#x", val);
+	if (val & ISAC_CIR0_CIC0) {
+		DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
+		FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
+	}
+	if (val & ISAC_CIR0_CIC1) {
+		val = isac->read_isac(isac, ISAC_CIR1);
+		DBG(DBG_WARN, "ISAC CIR1 %#x", val );
+	}
+}
+
+static inline void isac_rme_interrupt(struct isac *isac)
+{
+	unsigned char val;
+	int count;
+	struct sk_buff *skb;
+	
+	val = isac->read_isac(isac, ISAC_RSTA);
+	if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB) )
+	     != ISAC_RSTA_CRC) {
+		DBG(DBG_WARN, "RSTA %#x, dropped", val);
+		isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
+		goto out;
+	}
+
+	count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
+	DBG(DBG_IRQ, "RBCL %#x", count);
+	if (count == 0)
+		count = 0x20;
+
+	isac_empty_fifo(isac, count);
+	count = isac->rcvidx;
+	if (count < 1) {
+		DBG(DBG_WARN, "count %d < 1", count);
+		goto out;
+	}
+
+	skb = alloc_skb(count, GFP_ATOMIC);
+	if (!skb) {
+		DBG(DBG_WARN, "no memory, dropping\n");
+		goto out;
+	}
+	memcpy(skb_put(skb, count), isac->rcvbuf, count);
+	DBG_SKB(DBG_RPACKET, skb);
+	D_L1L2(isac, PH_DATA | INDICATION, skb);
+ out:
+	isac->rcvidx = 0;
+}
+
+static inline void isac_xpr_interrupt(struct isac *isac)
+{
+	if (!isac->tx_skb)
+		return;
+
+	if (isac->tx_skb->len > 0) {
+		isac_fill_fifo(isac);
+		return;
+	}
+	dev_kfree_skb_irq(isac->tx_skb);
+	isac->tx_cnt = 0;
+	isac->tx_skb = NULL;
+	D_L1L2(isac, PH_DATA | CONFIRM, NULL);
+}
+
+static inline void isac_exi_interrupt(struct isac *isac)
+{
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISAC_EXIR);
+	DBG(2, "EXIR %#x", val);
+
+	if (val & ISAC_EXIR_XMR) {
+		DBG(DBG_WARN, "ISAC XMR");
+		isac_retransmit(isac);
+	}
+	if (val & ISAC_EXIR_XDU) {
+		DBG(DBG_WARN, "ISAC XDU");
+		isac_retransmit(isac);
+	}
+	if (val & ISAC_EXIR_MOS) {  /* MOS */
+		DBG(DBG_WARN, "MOS");
+		val = isac->read_isac(isac, ISAC_MOSR);
+		DBG(2, "ISAC MOSR %#x", val);
+	}
+}
+
+void isac_irq(struct isac *isac)
+{
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISAC_ISTA);
+	DBG(DBG_IRQ, "ISTA %#x", val);
+
+	if (val & ISAC_ISTA_EXI) {
+		DBG(DBG_IRQ, "EXI");
+		isac_exi_interrupt(isac);
+	}
+	if (val & ISAC_ISTA_XPR) {
+		DBG(DBG_IRQ, "XPR");
+		isac_xpr_interrupt(isac);
+	}
+	if (val & ISAC_ISTA_RME) {
+		DBG(DBG_IRQ, "RME");
+		isac_rme_interrupt(isac);
+	}
+	if (val & ISAC_ISTA_RPF) {
+		DBG(DBG_IRQ, "RPF");
+		isac_empty_fifo(isac, 0x20);
+	}
+	if (val & ISAC_ISTA_CISQ) {
+		DBG(DBG_IRQ, "CISQ");
+		isac_cisq_interrupt(isac);
+	}
+	if (val & ISAC_ISTA_RSC) {
+		DBG(DBG_WARN, "RSC");
+	}
+	if (val & ISAC_ISTA_SIN) {
+		DBG(DBG_WARN, "SIN");
+	}
+	isac->write_isac(isac, ISAC_MASK, 0xff);
+	isac->write_isac(isac, ISAC_MASK, 0x00);
+}
+
+// ======================================================================
+
+static inline void isacsx_cic_interrupt(struct isac *isac)
+{
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISACSX_CIR0);
+	DBG(DBG_IRQ, "CIR0 %#x", val);
+	if (val & ISACSX_CIR0_CIC0) {
+		DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
+		FsmEvent(&isac->l1m, val >> 4, NULL);
+	}
+}
+
+static inline void isacsx_rme_interrupt(struct isac *isac)
+{
+	int count;
+	struct sk_buff *skb;
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISACSX_RSTAD);
+	if ((val & (ISACSX_RSTAD_VFR | 
+		    ISACSX_RSTAD_RDO | 
+		    ISACSX_RSTAD_CRC | 
+		    ISACSX_RSTAD_RAB)) 
+	    != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
+		DBG(DBG_WARN, "RSTAD %#x, dropped", val);
+		isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
+		goto out;
+	}
+
+	count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
+	DBG(DBG_IRQ, "RBCLD %#x", count);
+	if (count == 0)
+		count = 0x20;
+
+	isac_empty_fifo(isac, count);
+	// strip trailing status byte
+	count = isac->rcvidx - 1;
+	if (count < 1) {
+		DBG(DBG_WARN, "count %d < 1", count);
+		goto out;
+	}
+
+	skb = dev_alloc_skb(count);
+	if (!skb) {
+		DBG(DBG_WARN, "no memory, dropping");
+		goto out;
+	}
+	memcpy(skb_put(skb, count), isac->rcvbuf, count);
+	DBG_SKB(DBG_RPACKET, skb);
+	D_L1L2(isac, PH_DATA | INDICATION, skb);
+ out:
+	isac->rcvidx = 0;
+}
+
+static inline void isacsx_xpr_interrupt(struct isac *isac)
+{
+	if (!isac->tx_skb)
+		return;
+
+	if (isac->tx_skb->len > 0) {
+		isac_fill_fifo(isac);
+		return;
+	}
+	dev_kfree_skb_irq(isac->tx_skb);
+	isac->tx_skb = NULL;
+	isac->tx_cnt = 0;
+	D_L1L2(isac, PH_DATA | CONFIRM, NULL);
+}
+
+static inline void isacsx_icd_interrupt(struct isac *isac)
+{
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISACSX_ISTAD);
+	DBG(DBG_IRQ, "ISTAD %#x", val);
+	if (val & ISACSX_ISTAD_XDU) {
+		DBG(DBG_WARN, "ISTAD XDU");
+		isac_retransmit(isac);
+	}
+	if (val & ISACSX_ISTAD_XMR) {
+		DBG(DBG_WARN, "ISTAD XMR");
+		isac_retransmit(isac);
+	}
+	if (val & ISACSX_ISTAD_XPR) {
+		DBG(DBG_IRQ, "ISTAD XPR");
+		isacsx_xpr_interrupt(isac);
+	}
+	if (val & ISACSX_ISTAD_RFO) {
+		DBG(DBG_WARN, "ISTAD RFO");
+		isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
+	}
+	if (val & ISACSX_ISTAD_RME) {
+		DBG(DBG_IRQ, "ISTAD RME");
+		isacsx_rme_interrupt(isac);
+	}
+	if (val & ISACSX_ISTAD_RPF) {
+		DBG(DBG_IRQ, "ISTAD RPF");
+		isac_empty_fifo(isac, 0x20);
+	}
+}
+
+void isacsx_irq(struct isac *isac)
+{
+	unsigned char val;
+
+	val = isac->read_isac(isac, ISACSX_ISTA);
+	DBG(DBG_IRQ, "ISTA %#x", val);
+
+	if (val & ISACSX_ISTA_ICD)
+		isacsx_icd_interrupt(isac);
+	if (val & ISACSX_ISTA_CIC)
+		isacsx_cic_interrupt(isac);
+}
+
+void isac_init(struct isac *isac)
+{
+	isac->tx_skb = NULL;
+	isac->l1m.fsm = &l1fsm;
+	isac->l1m.state = ST_L1_RESET;
+#ifdef CONFIG_HISAX_DEBUG
+	isac->l1m.debug = 1;
+#else
+	isac->l1m.debug = 0;
+#endif
+	isac->l1m.userdata = isac;
+	isac->l1m.printdebug = l1m_debug;
+	FsmInitTimer(&isac->l1m, &isac->timer);
+}
+
+void isac_setup(struct isac *isac)
+{
+	int val, eval;
+
+	isac->type = TYPE_ISAC;
+	isac_version(isac);
+
+	ph_command(isac, ISAC_CMD_RES);
+
+  	isac->write_isac(isac, ISAC_MASK, 0xff);
+  	isac->mocr = 0xaa;
+	if (test_bit(ISAC_IOM1, &isac->flags)) {
+		/* IOM 1 Mode */
+		isac->write_isac(isac, ISAC_ADF2, 0x0);
+		isac->write_isac(isac, ISAC_SPCR, 0xa);
+		isac->write_isac(isac, ISAC_ADF1, 0x2);
+		isac->write_isac(isac, ISAC_STCR, 0x70);
+		isac->write_isac(isac, ISAC_MODE, 0xc9);
+	} else {
+		/* IOM 2 Mode */
+		if (!isac->adf2)
+			isac->adf2 = 0x80;
+		isac->write_isac(isac, ISAC_ADF2, isac->adf2);
+		isac->write_isac(isac, ISAC_SQXR, 0x2f);
+		isac->write_isac(isac, ISAC_SPCR, 0x00);
+		isac->write_isac(isac, ISAC_STCR, 0x70);
+		isac->write_isac(isac, ISAC_MODE, 0xc9);
+		isac->write_isac(isac, ISAC_TIMR, 0x00);
+		isac->write_isac(isac, ISAC_ADF1, 0x00);
+	}
+	val = isac->read_isac(isac, ISAC_STAR);
+	DBG(2, "ISAC STAR %x", val);
+	val = isac->read_isac(isac, ISAC_MODE);
+	DBG(2, "ISAC MODE %x", val);
+	val = isac->read_isac(isac, ISAC_ADF2);
+	DBG(2, "ISAC ADF2 %x", val);
+	val = isac->read_isac(isac, ISAC_ISTA);
+	DBG(2, "ISAC ISTA %x", val);
+	if (val & 0x01) {
+		eval = isac->read_isac(isac, ISAC_EXIR);
+		DBG(2, "ISAC EXIR %x", eval);
+	}
+	val = isac->read_isac(isac, ISAC_CIR0);
+	DBG(2, "ISAC CIR0 %x", val);
+	FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
+
+	isac->write_isac(isac, ISAC_MASK, 0x0);
+	// RESET Receiver and Transmitter
+	isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
+}
+
+void isacsx_setup(struct isac *isac)
+{
+	isac->type = TYPE_ISACSX;
+	// clear LDD
+	isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
+	// enable transmitter
+	isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
+	// transparent mode 0, RAC, stop/go
+	isac->write_isac(isac, ISACSX_MODED,    0xc9);
+	// all HDLC IRQ unmasked
+	isac->write_isac(isac, ISACSX_MASKD,    0x03);
+	// unmask ICD, CID IRQs
+	isac->write_isac(isac, ISACSX_MASK,            
+			 ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
+}
+
+void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
+{
+	struct isac *isac = hisax_d_if->priv;
+	struct sk_buff *skb = arg;
+
+	DBG(DBG_PR, "pr %#x", pr);
+
+	switch (pr) {
+	case PH_ACTIVATE | REQUEST:
+		FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
+		break;
+	case PH_DEACTIVATE | REQUEST:
+		FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
+		break;
+	case PH_DATA | REQUEST:
+		DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
+		DBG_SKB(DBG_XPACKET, skb);
+		if (isac->l1m.state != ST_L1_F7) {
+			DBG(1, "L1 wrong state %d\n", isac->l1m.state);
+			dev_kfree_skb(skb);
+			break;
+		}
+		if (isac->tx_skb)
+			BUG();
+
+		isac->tx_skb = skb;
+		isac_fill_fifo(isac);
+		break;
+	}
+}
+
+static int __init hisax_isac_init(void)
+{
+	printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
+
+	l1fsm.state_count = L1_STATE_COUNT;
+	l1fsm.event_count = L1_EVENT_COUNT;
+	l1fsm.strState = strL1State;
+	l1fsm.strEvent = strL1Event;
+	return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
+}
+
+static void __exit hisax_isac_exit(void)
+{
+	FsmFree(&l1fsm);
+}
+
+EXPORT_SYMBOL(isac_init);
+EXPORT_SYMBOL(isac_d_l2l1);
+
+EXPORT_SYMBOL(isacsx_setup);
+EXPORT_SYMBOL(isacsx_irq);
+
+EXPORT_SYMBOL(isac_setup);
+EXPORT_SYMBOL(isac_irq);
+
+module_init(hisax_isac_init);
+module_exit(hisax_isac_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hisax_isac.h linux/drivers/isdn/hisax/hisax_isac.h
--- linux-2.4.16/drivers/isdn/hisax/hisax_isac.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/isdn/hisax/hisax_isac.h	Thu Dec  6 19:04:52 2001
@@ -0,0 +1,45 @@
+#ifndef __HISAX_ISAC_H__
+#define __HISAX_ISAC_H__
+
+#include <linux/kernel.h>
+#include "fsm.h"
+#include "hisax_if.h"
+
+#define TIMER3_VALUE 7000
+#define MAX_DFRAME_LEN_L1 300
+
+#define ISAC_IOM1	0
+
+struct isac {
+	void *priv;
+
+	u_long flags;
+	struct hisax_d_if hisax_d_if;
+	struct FsmInst l1m;
+	struct FsmTimer timer;
+	u_char mocr;
+	u_char adf2;
+	int    type;
+
+	u_char rcvbuf[MAX_DFRAME_LEN_L1];
+	int rcvidx;
+
+	struct sk_buff *tx_skb;
+	int tx_cnt;
+
+	u_char (*read_isac)      (struct isac *, u_char);
+	void   (*write_isac)     (struct isac *, u_char, u_char);
+	void   (*read_isac_fifo) (struct isac *, u_char *, int);
+	void   (*write_isac_fifo)(struct isac *, u_char *, int);
+};
+
+void isac_init(struct isac *isac);
+void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
+
+void isac_setup(struct isac *isac);
+void isac_irq(struct isac *isac);
+
+void isacsx_setup(struct isac *isac);
+void isacsx_irq(struct isac *isac);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c
--- linux-2.4.16/drivers/isdn/hisax/hscx.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hscx.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hscx.c,v 1.21.6.3 2001/09/23 22:24:48 kai Exp $
+/* $Id: hscx.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * HSCX specific routines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hscx.h linux/drivers/isdn/hisax/hscx.h
--- linux-2.4.16/drivers/isdn/hisax/hscx.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hscx.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hscx.h,v 1.6.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hscx.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * HSCX specific defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c
--- linux-2.4.16/drivers/isdn/hisax/hscx_irq.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/hscx_irq.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.16.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hscx_irq.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level b-channel stuff for Siemens HSCX
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c
--- linux-2.4.16/drivers/isdn/hisax/icc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/icc.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: icc.c,v 1.5.6.4 2001/09/23 22:24:48 kai Exp $
+/* $Id: icc.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * ICC specific routines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/icc.h linux/drivers/isdn/hisax/icc.h
--- linux-2.4.16/drivers/isdn/hisax/icc.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/icc.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: icc.h,v 1.2.6.3 2001/09/23 22:24:48 kai Exp $
+/* $Id: icc.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * ICC specific routines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/ipac.h linux/drivers/isdn/hisax/ipac.h
--- linux-2.4.16/drivers/isdn/hisax/ipac.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/ipac.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: ipac.h,v 1.5.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: ipac.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * IPAC specific defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c
--- linux-2.4.16/drivers/isdn/hisax/isac.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isac.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isac.c,v 1.28.6.3 2001/09/23 22:24:49 kai Exp $
+/* $Id: isac.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * ISAC specific routines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isac.h linux/drivers/isdn/hisax/isac.h
--- linux-2.4.16/drivers/isdn/hisax/isac.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isac.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isac.h,v 1.7.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isac.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * ISAC specific defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- linux-2.4.16/drivers/isdn/hisax/isar.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isar.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.17.6.5 2001/09/23 11:51:33 keil Exp $
+/* $Id: isar.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h
--- linux-2.4.16/drivers/isdn/hisax/isar.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isar.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isar.h,v 1.9.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isar.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * ISAR (Siemens PSB 7110) specific defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- linux-2.4.16/drivers/isdn/hisax/isdnl1.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isdnl1.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.41.6.5 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl1.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * common low level stuff for Siemens Chipsetbased isdn cards
  *
@@ -18,7 +18,7 @@
  *
  */
 
-const char *l1_revision = "$Revision: 2.41.6.5 $";
+const char *l1_revision = "$Revision: 1.1.4.1 $";
 
 #define __NO_VERSION__
 #include <linux/init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h
--- linux-2.4.16/drivers/isdn/hisax/isdnl1.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isdnl1.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.h,v 2.9.6.3 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl1.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Layer 1 defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- linux-2.4.16/drivers/isdn/hisax/isdnl2.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isdnl2.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 2.25.6.4 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl2.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Author       Karsten Keil
  *              based on the teles driver from Jan den Ouden
@@ -20,7 +20,7 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.25.6.4 $";
+const char *l2_revision = "$Revision: 1.1.4.1 $";
 
 static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h
--- linux-2.4.16/drivers/isdn/hisax/isdnl2.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isdnl2.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl2.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Layer 2 defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- linux-2.4.16/drivers/isdn/hisax/isdnl3.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isdnl3.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 2.17.6.5 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl3.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Author       Karsten Keil
  *              based on the teles driver from Jan den Ouden
@@ -21,7 +21,7 @@
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.17.6.5 $";
+const char *l3_revision = "$Revision: 1.1.4.1 $";
 
 static struct Fsm l3fsm;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h
--- linux-2.4.16/drivers/isdn/hisax/isdnl3.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isdnl3.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.h,v 2.6.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl3.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c
--- linux-2.4.16/drivers/isdn/hisax/isurf.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/isurf.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isurf.c,v 1.10.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isurf.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Siemens I-Surf/I-Talk cards
  *
@@ -19,7 +19,7 @@
 
 extern const char *CardType[];
 
-static const char *ISurf_revision = "$Revision: 1.10.6.2 $";
+static const char *ISurf_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c
--- linux-2.4.16/drivers/isdn/hisax/ix1_micro.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/ix1_micro.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 2.10.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: ix1_micro.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for ITK ix1-micro Rev.2 isdn cards
  * derived from the original file teles3.c from Karsten Keil
@@ -25,7 +25,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.10.6.2 $";
+const char *ix1_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c
--- linux-2.4.16/drivers/isdn/hisax/jade.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/jade.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: jade.c,v 1.6.6.3 2001/09/23 22:24:49 kai Exp $
+/* $Id: jade.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * JADE stuff (derived from original hscx.c)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/jade.h linux/drivers/isdn/hisax/jade.h
--- linux-2.4.16/drivers/isdn/hisax/jade.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/jade.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: jade.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: jade.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * JADE specific defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/jade_irq.c linux/drivers/isdn/hisax/jade_irq.c
--- linux-2.4.16/drivers/isdn/hisax/jade_irq.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/jade_irq.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: jade_irq.c,v 1.5.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: jade_irq.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Low level JADE IRQ stuff (derived from original hscx_irq.c)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c
--- linux-2.4.16/drivers/isdn/hisax/l3_1tr6.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/l3_1tr6.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 2.13.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: l3_1tr6.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * German 1TR6 D-channel protocol
  *
@@ -20,7 +20,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.13.6.2 $";
+const char *l3_1tr6_revision = "$Revision: 1.1.4.1 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
 	*ptr++ = dis; \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h
--- linux-2.4.16/drivers/isdn/hisax/l3_1tr6.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/l3_1tr6.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.h,v 2.2.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: l3_1tr6.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * German 1TR6 D-channel protocol defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c
--- linux-2.4.16/drivers/isdn/hisax/l3dss1.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/l3dss1.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.30.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: l3dss1.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * EURO/DSS1 D-channel protocol
  *
@@ -27,7 +27,7 @@
 #include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.30.6.2 $";
+const char *dss1_revision = "$Revision: 1.1.4.1 $";
 
 #define EXT_BEARER_CAPS 1
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/l3dss1.h linux/drivers/isdn/hisax/l3dss1.h
--- linux-2.4.16/drivers/isdn/hisax/l3dss1.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/l3dss1.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.h,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $
+/* $Id: l3dss1.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * DSS1 (Euro) D-channel protocol defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/l3ni1.c linux/drivers/isdn/hisax/l3ni1.c
--- linux-2.4.16/drivers/isdn/hisax/l3ni1.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/l3ni1.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: l3ni1.c,v 2.5.6.3 2001/09/23 22:24:50 kai Exp $
+/* $Id: l3ni1.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * NI1 D-channel protocol
  *
@@ -25,7 +25,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *ni1_revision = "$Revision: 2.5.6.3 $";
+const char *ni1_revision = "$Revision: 1.1.4.1 $";
 
 #define EXT_BEARER_CAPS 1
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/l3ni1.h linux/drivers/isdn/hisax/l3ni1.h
--- linux-2.4.16/drivers/isdn/hisax/l3ni1.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/l3ni1.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: l3ni1.h,v 2.3.6.2 2001/09/23 22:24:50 kai Exp $
+/* $Id: l3ni1.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * NI1 D-channel protocol
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/lmgr.c linux/drivers/isdn/hisax/lmgr.c
--- linux-2.4.16/drivers/isdn/hisax/lmgr.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/lmgr.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: lmgr.c,v 1.7.6.2 2001/09/23 22:24:50 kai Exp $
+/* $Id: lmgr.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Layermanagement module
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c
--- linux-2.4.16/drivers/isdn/hisax/mic.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/mic.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: mic.c,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $
+/* $Id: mic.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for mic cards
  *
@@ -19,7 +19,7 @@
 
 extern const char *CardType[];
 
-const char *mic_revision = "$Revision: 1.10.6.2 $";
+const char *mic_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- linux-2.4.16/drivers/isdn/hisax/netjet.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/netjet.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.24.6.6 2001/09/23 22:24:50 kai Exp $
+/* $Id: netjet.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Traverse Technologie NETJet ISDN cards
  *
@@ -24,7 +24,7 @@
 #include <asm/io.h>
 #include "netjet.h"
 
-const char *NETjet_revision = "$Revision: 1.24.6.6 $";
+const char *NETjet_revision = "$Revision: 1.1.4.1 $";
 
 /* Interface functions */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/netjet.h linux/drivers/isdn/hisax/netjet.h
--- linux-2.4.16/drivers/isdn/hisax/netjet.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/netjet.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: netjet.h,v 2.5.6.3 2001/09/23 22:24:50 kai Exp $
+/* $Id: netjet.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * NETjet common header file
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- linux-2.4.16/drivers/isdn/hisax/niccy.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/niccy.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: niccy.c,v 1.15.6.6 2001/10/20 22:08:24 kai Exp $
+/* $Id: niccy.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
  * compatible (SAGEM cybermodem)
@@ -24,7 +24,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.15.6.6 $";
+const char *niccy_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c
--- linux-2.4.16/drivers/isdn/hisax/nj_s.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/nj_s.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: nj_s.c,v 2.7.6.6 2001/09/23 22:24:50 kai Exp $
+/* $Id: nj_s.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -16,7 +16,7 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_S_revision = "$Revision: 2.7.6.6 $";
+const char *NETjet_S_revision = "$Revision: 1.1.4.1 $";
 
 static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c
--- linux-2.4.16/drivers/isdn/hisax/nj_u.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/nj_u.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: nj_u.c,v 2.8.6.6 2001/09/23 22:24:50 kai Exp $ 
+/* $Id: nj_u.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $ 
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -16,7 +16,7 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_U_revision = "$Revision: 2.8.6.6 $";
+const char *NETjet_U_revision = "$Revision: 1.1.4.1 $";
 
 static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c
--- linux-2.4.16/drivers/isdn/hisax/q931.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/q931.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.10.6.3 2001/09/23 22:24:50 kai Exp $
+/* $Id: q931.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * code to decode ITU Q.931 call control messages
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/rawhdlc.c linux/drivers/isdn/hisax/rawhdlc.c
--- linux-2.4.16/drivers/isdn/hisax/rawhdlc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/rawhdlc.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: rawhdlc.c,v 1.5.6.2 2001/09/23 22:24:51 kai Exp $
+/* $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
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/rawhdlc.h linux/drivers/isdn/hisax/rawhdlc.h
--- linux-2.4.16/drivers/isdn/hisax/rawhdlc.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/rawhdlc.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: rawhdlc.h,v 1.3.6.2 2001/09/23 22:24:51 kai Exp $
+/* $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>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c
--- linux-2.4.16/drivers/isdn/hisax/s0box.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/s0box.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: s0box.c,v 2.4.6.2 2001/09/23 22:24:51 kai Exp $
+/* $Id: s0box.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Creatix S0BOX
  *
@@ -18,7 +18,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.4.6.2 $";
+const char *s0box_revision = "$Revision: 1.1.4.1 $";
 
 static inline void
 writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c
--- linux-2.4.16/drivers/isdn/hisax/saphir.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/saphir.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: saphir.c,v 1.8.6.2 2001/09/23 22:24:51 kai Exp $
+/* $Id: saphir.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for HST Saphir 1
  *
@@ -20,7 +20,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static char *saphir_rev = "$Revision: 1.8.6.2 $";
+static char *saphir_rev = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- linux-2.4.16/drivers/isdn/hisax/sedlbauer.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/sedlbauer.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.25.6.6 2001/09/23 22:24:51 kai Exp $
+/* $Id: sedlbauer.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Sedlbauer cards
  * includes support for the Sedlbauer speed star (speed star II),
@@ -51,7 +51,7 @@
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.25.6.6 $";
+const char *Sedlbauer_revision = "$Revision: 1.1.4.1 $";
 
 const char *Sedlbauer_Types[] =
 	{"None", "speed card/win", "speed star", "speed fax+",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c
--- linux-2.4.16/drivers/isdn/hisax/sportster.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/sportster.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: sportster.c,v 1.14.6.2 2001/09/23 22:24:51 kai Exp $
+/* $Id: sportster.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for USR Sportster internal TA
  *
@@ -20,7 +20,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.14.6.2 $";
+const char *sportster_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/st5481_b.c linux/drivers/isdn/hisax/st5481_b.c
--- linux-2.4.16/drivers/isdn/hisax/st5481_b.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/st5481_b.c	Thu Dec  6 19:04:52 2001
@@ -275,7 +275,7 @@
 				      usb_b_out_complete, bcs);
 }
 
-static void __devexit st5481_release_b_out(struct st5481_bcs *bcs)
+static void st5481_release_b_out(struct st5481_bcs *bcs)
 {
 	struct st5481_b_out *b_out = &bcs->b_out;
 
@@ -316,7 +316,7 @@
 /*
  * Release buffers and URBs for the B channels
  */
-void __devexit st5481_release_b(struct st5481_bcs *bcs)
+void st5481_release_b(struct st5481_bcs *bcs)
 {
 	DBG(4,"");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/st5481_d.c linux/drivers/isdn/hisax/st5481_d.c
--- linux-2.4.16/drivers/isdn/hisax/st5481_d.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/st5481_d.c	Thu Dec  6 19:04:52 2001
@@ -673,7 +673,7 @@
 				      usb_d_out_complete, adapter);
 }
 
-static void __devexit st5481_release_d_out(struct st5481_adapter *adapter)
+static void st5481_release_d_out(struct st5481_adapter *adapter)
 {
 	struct st5481_d_out *d_out = &adapter->d_out;
 
@@ -723,7 +723,7 @@
 	return retval;
 }
 
-void __devexit st5481_release_d(struct st5481_adapter *adapter)
+void st5481_release_d(struct st5481_adapter *adapter)
 {
 	DBG(2,"");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/st5481_init.c linux/drivers/isdn/hisax/st5481_init.c
--- linux-2.4.16/drivers/isdn/hisax/st5481_init.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/st5481_init.c	Fri Dec  7 18:08:43 2001
@@ -178,7 +178,7 @@
 static struct usb_driver st5481_usb_driver = {
 	name: "st5481_usb",
 	probe: probe_st5481,
-	disconnect: disconnect_st5481,
+	disconnect: __devexit_p(disconnect_st5481),
 	id_table: st5481_ids,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/st5481_usb.c linux/drivers/isdn/hisax/st5481_usb.c
--- linux-2.4.16/drivers/isdn/hisax/st5481_usb.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/st5481_usb.c	Thu Dec  6 19:04:52 2001
@@ -307,7 +307,7 @@
  * Release buffers and URBs for the interrupt and control
  * endpoint.
  */
-void __devexit st5481_release_usb(struct st5481_adapter *adapter)
+void st5481_release_usb(struct st5481_adapter *adapter)
 {
 	struct st5481_intr *intr = &adapter->intr;
 	struct st5481_ctrl *ctrl = &adapter->ctrl;
@@ -443,7 +443,7 @@
 	return retval;
 }
 
-void __devexit st5481_release_isocpipes(struct urb* urb[2])
+void st5481_release_isocpipes(struct urb* urb[2])
 {
 	int j;
 
@@ -547,7 +547,7 @@
 	return retval;
 }
 
-void __devexit st5481_release_in(struct st5481_in *in)
+void st5481_release_in(struct st5481_in *in)
 {
 	DBG(2,"");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c
--- linux-2.4.16/drivers/isdn/hisax/tei.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/tei.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 2.17.6.3 2001/09/23 22:24:51 kai Exp $
+/* $Id: tei.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Author       Karsten Keil
  *              based on the teles driver from Jan den Ouden
@@ -21,7 +21,7 @@
 #include <linux/init.h>
 #include <linux/random.h>
 
-const char *tei_revision = "$Revision: 2.17.6.3 $";
+const char *tei_revision = "$Revision: 1.1.4.1 $";
 
 #define ID_REQUEST	1
 #define ID_ASSIGNED	2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c
--- linux-2.4.16/drivers/isdn/hisax/teleint.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/teleint.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: teleint.c,v 1.14.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: teleint.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for TeleInt isdn cards
  *
@@ -19,7 +19,7 @@
 
 extern const char *CardType[];
 
-const char *TeleInt_revision = "$Revision: 1.14.6.2 $";
+const char *TeleInt_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- linux-2.4.16/drivers/isdn/hisax/teles0.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/teles0.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.13.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: teles0.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Teles Memory IO isdn cards
  *
@@ -24,7 +24,7 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.13.6.2 $";
+const char *teles0_revision = "$Revision: 1.1.4.1 $";
 
 #define TELES_IOMEM_SIZE	0x400
 #define byteout(addr,val) outb(val,addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- linux-2.4.16/drivers/isdn/hisax/teles3.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/teles3.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 2.17.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: teles3.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Teles 16.3 & PNP isdn cards
  *
@@ -21,7 +21,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.17.6.2 $";
+const char *teles3_revision = "$Revision: 1.1.4.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c
--- linux-2.4.16/drivers/isdn/hisax/telespci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/telespci.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: telespci.c,v 2.16.6.5 2001/09/23 22:24:52 kai Exp $
+/* $Id: telespci.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * low level stuff for Teles PCI isdn cards
  *
@@ -22,7 +22,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.16.6.5 $";
+const char *telespci_revision = "$Revision: 1.1.4.1 $";
 
 #define ZORAN_PO_RQ_PEN	0x02000000
 #define ZORAN_PO_WR	0x00800000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c
--- linux-2.4.16/drivers/isdn/hisax/w6692.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/w6692.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: w6692.c,v 1.12.6.6 2001/09/23 22:24:52 kai Exp $
+/* $Id: w6692.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Winbond W6692 specific routines
  *
@@ -36,7 +36,7 @@
 
 extern const char *CardType[];
 
-const char *w6692_revision = "$Revision: 1.12.6.6 $";
+const char *w6692_revision = "$Revision: 1.1.4.1 $";
 
 #define DBUSY_TIMER_VALUE 80
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hisax/w6692.h linux/drivers/isdn/hisax/w6692.h
--- linux-2.4.16/drivers/isdn/hisax/w6692.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hisax/w6692.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: w6692.h,v 1.2.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: w6692.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  *
  * Winbond W6692 specific defines
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c
--- linux-2.4.16/drivers/isdn/hysdn/boardergo.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/boardergo.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: boardergo.c,v 1.5.6.7 2001/11/06 21:58:19 kai Exp $
+/* $Id: boardergo.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, specific routines for ergo type boards.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/boardergo.h linux/drivers/isdn/hysdn/boardergo.h
--- linux-2.4.16/drivers/isdn/hysdn/boardergo.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/boardergo.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: boardergo.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $
+/* $Id: boardergo.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c
--- linux-2.4.16/drivers/isdn/hysdn/hycapi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hycapi.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hycapi.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
+/* $Id: hycapi.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, CAPI2.0-Interface.
  *
@@ -29,7 +29,7 @@
 #include "hysdn_defs.h"
 #include <linux/kernelcapi.h>
 
-static char hycapi_revision[]="$Revision: 1.8.6.4 $";
+static char hycapi_revision[]="$Revision: 1.1.4.1 $";
 
 unsigned int hycapi_enable = 0xffffffff; 
 MODULE_PARM(hycapi_enable, "i");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_boot.c linux/drivers/isdn/hysdn/hysdn_boot.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_boot.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_boot.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_boot.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards
  * specific routines for booting and pof handling
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_defs.h linux/drivers/isdn/hysdn/hysdn_defs.h
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_defs.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_defs.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_defs.h,v 1.5.6.3 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_defs.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards
  * global definitions and exported vars and functions.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_init.c linux/drivers/isdn/hysdn/hysdn_init.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_init.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_init.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_init.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, init functions.
  *
@@ -33,7 +33,7 @@
 MODULE_AUTHOR("Werner Cornelius");
 MODULE_LICENSE("GPL");
 
-static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
+static char *hysdn_init_revision = "$Revision: 1.1.4.1 $";
 int cardmax;			/* number of found cards */
 hysdn_card *card_root = NULL;	/* pointer to first card */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_net.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_net.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_net.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_net.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, net (ethernet type) handling routines.
  *
@@ -29,7 +29,7 @@
 MODULE_PARM(hynet_enable, "i");
 
 /* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
+char *hysdn_net_revision = "$Revision: 1.1.4.1 $";
 
 #define MAX_SKB_BUFFERS 20	/* number of buffers for keeping TX-data */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_pof.h linux/drivers/isdn/hysdn/hysdn_pof.h
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_pof.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_pof.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_pof.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_pof.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, definitions used for handling pof-files.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_procconf.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_procconf.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_procconf.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_procconf.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
  *
@@ -21,7 +21,7 @@
 
 #include "hysdn_defs.h"
 
-static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $";
+static char *hysdn_procconf_revision = "$Revision: 1.1.4.1 $";
 
 #define INFO_OUT_LEN 80		/* length of info line including lf */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_procfs.c linux/drivers/isdn/hysdn/hysdn_procfs.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_procfs.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_procfs.c	Thu Jan  1 00:00:00 1970
@@ -1,471 +0,0 @@
-/* $Id: hysdn_procfs.c,v 1.1 2000/02/10 19:45:18 werner Exp $
-
- * Linux driver for HYSDN cards, /proc/net filesystem log functions.
- * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
- *
- * Copyright 1999  by Werner Cornelius (werner@titro.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, 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.
- *
- * $Log: hysdn_procfs.c,v $
- * Revision 1.1  2000/02/10 19:45:18  werner
- *
- * Initial release
- *
- *
- */
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-
-#include "hysdn_defs.h"
-
-static char *hysdn_procfs_revision = "$Revision: 1.1 $";
-
-#define INFO_OUT_LEN 80		/* length of info line including lf */
-
-/*************************************************/
-/* structure keeping ascii log for device output */
-/*************************************************/
-struct log_data {
-	struct log_data *next;
-	ulong usage_cnt;	/* number of files still to work */
-	void *proc_ctrl;	/* pointer to own control procdata structure */
-	char log_start[2];	/* log string start (final len aligned by size) */
-};
-
-/**********************************************/
-/* structure holding proc entrys for one card */
-/**********************************************/
-struct procdata {
-	struct proc_dir_entry *log;	/* log entry */
-	char log_name[15];	/* log filename */
-	struct log_data *log_head, *log_tail;	/* head and tail for queue */
-	int if_used;		/* open count for interface */
-	wait_queue_head_t rd_queue;
-};
-
-/********************************************/
-/* put an log buffer into the log queue.    */
-/* This buffer will be kept until all files */
-/* opened for read got the contents.        */
-/* Flushes buffers not longer in use.       */
-/********************************************/
-void
-put_log_buffer(hysdn_card * card, char *cp)
-{
-	struct log_data *ib;
-	struct procdata *pd = card->procfs;
-	int flags;
-
-	if (!pd)
-		return;
-	if (!cp)
-		return;
-	if (!*cp)
-		return;
-	if (pd->if_used <= 0)
-		return;		/* no open file for read */
-
-	if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
-		 return;	/* no memory */
-	strcpy(ib->log_start, cp);	/* set output string */
-	ib->next = NULL;
-	ib->proc_ctrl = pd;	/* point to own control structure */
-	save_flags(flags);
-	cli();
-	ib->usage_cnt = pd->if_used;
-	if (!pd->log_head)
-		pd->log_head = ib;	/* new head */
-	else
-		pd->log_tail->next = ib;	/* follows existing messages */
-	pd->log_tail = ib;	/* new tail */
-	restore_flags(flags);
-
-	/* delete old entrys */
-	while (pd->log_head->next) {
-		if ((pd->log_head->usage_cnt <= 0) &&
-		    (pd->log_head->next->usage_cnt <= 0)) {
-			ib = pd->log_head;
-			pd->log_head = pd->log_head->next;
-			kfree(ib);
-		} else
-			break;
-	}			/* pd->log_head->next */
-	wake_up_interruptible(&(pd->rd_queue));		/* announce new entry */
-}				/* put_log_buffer */
-
-
-/**********************************/
-/* log file operations and tables */
-/**********************************/
-
-/****************************************/
-/* write log file -> set log level bits */
-/****************************************/
-static ssize_t
-hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
-{
-	int retval;
-	hysdn_card *card = (hysdn_card *) file->private_data;
-
-	if (&file->f_pos != off)	/* fs error check */
-		return (-ESPIPE);
-
-	if ((retval = pof_boot_write(card, buf, count)) < 0)
-		retval = -EFAULT;	/* an error occurred */
-
-	return (retval);
-}				/* hysdn_log_write */
-
-/******************/
-/* read log file */
-/******************/
-static ssize_t
-hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
-{
-	struct log_data *inf;
-	int len;
-	word ino;
-	struct procdata *pd;
-	hysdn_card *card;
-
-	if (!*((struct log_data **) file->private_data)) {
-		if (file->f_flags & O_NONBLOCK)
-			return (-EAGAIN);
-
-		/* sorry, but we need to search the card */
-		ino = file->f_dentry->d_inode->i_ino & 0xFFFF;	/* low-ino */
-		card = card_root;
-		while (card) {
-			pd = card->procfs;
-			if (pd->log->low_ino == ino)
-				break;
-			card = card->next;	/* search next entry */
-		}
-		if (card)
-			interruptible_sleep_on(&(pd->rd_queue));
-		else
-			return (-EAGAIN);
-
-	}
-	if (!(inf = *((struct log_data **) file->private_data)))
-		return (0);
-
-	inf->usage_cnt--;	/* new usage count */
-	(struct log_data **) file->private_data = &inf->next;	/* next structure */
-	if ((len = strlen(inf->log_start)) <= count) {
-		if (copy_to_user(buf, inf->log_start, len))
-			return -EFAULT;
-		file->f_pos += len;
-		return (len);
-	}
-	return (0);
-}				/* hysdn_log_read */
-
-/******************/
-/* open log file */
-/******************/
-static int
-hysdn_log_open(struct inode *ino, struct file *filep)
-{
-	hysdn_card *card;
-	struct procdata *pd;
-	ulong flags;
-
-	lock_kernel();
-	card = card_root;
-	while (card) {
-		pd = card->procfs;
-		if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
-			break;
-		card = card->next;	/* search next entry */
-	}
-	if (!card) {
-		unlock_kernel();
-		return (-ENODEV);	/* device is unknown/invalid */
-	}
-	filep->private_data = card;	/* remember our own card */
-
-	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
-		/* write only access -> boot pof data */
-		if (pof_boot_open(card)) {
-			unlock_kernel();
-			return (-EPERM);	/* no permission this time */
-		}
-	} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
-
-		/* read access -> log/debug read */
-		save_flags(flags);
-		cli();
-		pd->if_used++;
-		if (pd->log_head)
-			(struct log_data **) filep->private_data = &(pd->log_tail->next);
-		else
-			(struct log_data **) filep->private_data = &(pd->log_head);
-		restore_flags(flags);
-
-	} else {		/* simultaneous read/write access forbidden ! */
-		unlock_kernel();
-		return (-EPERM);	/* no permission this time */
-	}
-	unlock_kernel();
-	return (0);
-}				/* hysdn_log_open */
-
-/*******************************************************************************/
-/* close a cardlog file. If the file has been opened for exclusive write it is */
-/* assumed as pof data input and the pof loader is noticed about.              */
-/* Otherwise file is handled as log output. In this case the interface usage   */
-/* count is decremented and all buffers are noticed of closing. If this file   */
-/* was the last one to be closed, all buffers are freed.                       */
-/*******************************************************************************/
-static int
-hysdn_log_close(struct inode *ino, struct file *filep)
-{
-	struct log_data *inf;
-	struct procdata *pd;
-	hysdn_card *card;
-	int flags, retval = 0;
-
-	lock_kernel();
-	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
-		/* write only access -> write debug completely written */
-		retval = 0;	/* success */
-	} else {
-		/* read access -> log/debug read, mark one further file as closed */
-
-		pd = NULL;
-		save_flags(flags);
-		cli();
-		inf = *((struct log_data **) filep->private_data);	/* get first log entry */
-		if (inf)
-			pd = (struct procdata *) inf->proc_ctrl;	/* still entries there */
-		else {
-			/* no info available -> search card */
-			card = card_root;
-			while (card) {
-				pd = card->procfs;
-				if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
-					break;
-				card = card->next;	/* search next entry */
-			}
-			if (card)
-				pd = card->procfs;	/* pointer to procfs ctrl */
-		}
-		if (pd)
-			pd->if_used--;	/* decrement interface usage count by one */
-
-		while (inf) {
-			inf->usage_cnt--;	/* decrement usage count for buffers */
-			inf = inf->next;
-		}
-		restore_flags(flags);
-
-		if (pd)
-			if (pd->if_used <= 0)	/* delete buffers if last file closed */
-				while (pd->log_head) {
-					inf = pd->log_head;
-					pd->log_head = pd->log_head->next;
-					kfree(inf);
-				}
-	}			/* read access */
-
-	unlock_kernel();
-	return (retval);
-}				/* hysdn_log_close */
-
-/*************************************************/
-/* select/poll routine to be able using select() */
-/*************************************************/
-static unsigned int
-hysdn_log_poll(struct file *file, poll_table * wait)
-{
-	unsigned int mask = 0;
-	word ino;
-	hysdn_card *card;
-	struct procdata *pd;
-
-	if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
-		return (mask);	/* no polling for write supported */
-
-	/* we need to search the card */
-	ino = file->f_dentry->d_inode->i_ino & 0xFFFF;	/* low-ino */
-	card = card_root;
-	while (card) {
-		pd = card->procfs;
-		if (pd->log->low_ino == ino)
-			break;
-		card = card->next;	/* search next entry */
-	}
-	if (!card)
-		return (mask);	/* card not found */
-
-	poll_wait(file, &(pd->rd_queue), wait);
-
-	if (*((struct log_data **) file->private_data))
-		mask |= POLLIN | POLLRDNORM;
-
-	return mask;
-}				/* hysdn_log_poll */
-
-/**************************************************/
-/* table for log filesystem functions defined above. */
-/**************************************************/
-static struct file_operations log_fops =
-{
-	llseek:		no_llseek,
-	read:		hysdn_log_read,
-	write:		hysdn_log_write,
-	poll:		hysdn_log_poll,
-	open:		hysdn_log_open,
-	release:	hysdn_log_close,
-};
-
-/*****************************************/
-/* Output info data to the cardinfo file */
-/*****************************************/
-static int
-info_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
-{
-	char tmp[INFO_OUT_LEN * 11 + 2];
-	int i;
-	char *cp;
-	hysdn_card *card;
-
-	sprintf(tmp, "id bus slot type irq iobase plx-mem    dp-mem     boot device");
-	cp = tmp;		/* start of string */
-	while (*cp)
-		cp++;
-	while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
-		*cp++ = ' ';
-	*cp++ = '\n';
-
-	card = card_root;	/* start of list */
-	while (card) {
-		sprintf(cp, "%d  %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x",
-			card->myid,
-			card->bus,
-			PCI_SLOT(card->devfn),
-			card->brdtype,
-			card->irq,
-			card->iobase,
-			card->plxbase,
-			card->membase);
-		card = card->next;
-		while (*cp)
-			cp++;
-		while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
-			*cp++ = ' ';
-		*cp++ = '\n';
-	}
-
-	i = cp - tmp;
-	*start = buffer;
-	if (offset + length > i) {
-		length = i - offset;
-		*eof = 1;
-	} else if (offset > i) {
-		length = 0;
-		*eof = 1;
-	}
-	cp = tmp + offset;
-
-	if (length > 0) {
-		/*   start_bh_atomic(); */
-		memcpy(buffer, cp, length);
-		/* end_bh_atomic(); */
-		return length;
-	}
-	return 0;
-}				/* info_read */
-
-/*****************************/
-/* hysdn subdir in /proc/net */
-/*****************************/
-static struct proc_dir_entry *hysdn_proc_entry = NULL;
-static struct proc_dir_entry *hysdn_info_entry = NULL;
-
-/***************************************************************************************/
-/* hysdn_procfs_init is called when the module is loaded and after the cards have been */
-/* detected. The needed proc dir and card entries are created.                         */
-/***************************************************************************************/
-int
-hysdn_procfs_init(void)
-{
-	struct procdata *pd;
-	hysdn_card *card;
-
-	hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
-	if (!hysdn_proc_entry) {
-		printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
-		return (-1);
-	}
-	hysdn_info_entry = create_proc_entry("cardinfo", 0, hysdn_proc_entry);
-	if (hysdn_info_entry)
-		hysdn_info_entry->read_proc = info_read;	/* read info function */
-
-	/* create all cardlog proc entries */
-
-	card = card_root;	/* start with first card */
-	while (card) {
-		if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
-			memset(pd, 0, sizeof(struct procdata));
-
-			sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
-			if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
-				pd->log->proc_fops = &log_fops;	/* set new operations table */
-				pd->log->owner = THIS_MODULE;
-			}
-
-			init_waitqueue_head(&(pd->rd_queue));
-
-			card->procfs = (void *) pd;	/* remember procfs structure */
-		}
-		card = card->next;	/* point to next card */
-	}
-
-	printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision));
-	return (0);
-}				/* hysdn_procfs_init */
-
-/***************************************************************************************/
-/* hysdn_procfs_release is called when the module is unloaded and before the cards     */
-/* resources are released. The module counter is assumed to be 0 !                     */
-/***************************************************************************************/
-void
-hysdn_procfs_release(void)
-{
-	struct procdata *pd;
-	hysdn_card *card;
-
-	card = card_root;	/* start with first card */
-	while (card) {
-		if ((pd = (struct procdata *) card->procfs) != NULL) {
-			if (pd->log)
-				remove_proc_entry(pd->log_name, hysdn_proc_entry);
-			kfree(pd);	/* release memory */
-		}
-		card = card->next;	/* point to next card */
-	}
-
-	remove_proc_entry("cardinfo", hysdn_proc_entry);
-	remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
-}				/* hysdn_procfs_release */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_proclog.c linux/drivers/isdn/hysdn/hysdn_proclog.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_proclog.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_proclog.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_proclog.c,v 1.9.6.3 2001/09/23 22:24:54 kai Exp $
+/* $Id: hysdn_proclog.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards, /proc/net filesystem log functions.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c
--- linux-2.4.16/drivers/isdn/hysdn/hysdn_sched.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/hysdn/hysdn_sched.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $
+/* $Id: hysdn_sched.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Linux driver for HYSDN cards
  * scheduler routines for handling exchange card <-> pc.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- linux-2.4.16/drivers/isdn/icn/icn.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/icn/icn.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
+/* $Id: icn.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -41,7 +41,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.65.6.8 $";
+*revision = "$Revision: 1.1.4.1 $";
 
 static int icn_addcard(int, char *, char *);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- linux-2.4.16/drivers/isdn/icn/icn.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/icn/icn.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.30.6.5 2001/09/23 22:24:55 kai Exp $
+/* $Id: icn.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c
--- linux-2.4.16/drivers/isdn/isdn_audio.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_audio.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_audio.c,v 1.21.6.2 2001/09/23 22:24:31 kai Exp $
+/* $Id: isdn_audio.c,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
  *
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
@@ -15,7 +15,7 @@
 #include "isdn_audio.h"
 #include "isdn_common.h"
 
-char *isdn_audio_revision = "$Revision: 1.21.6.2 $";
+char *isdn_audio_revision = "$Revision: 1.1.4.1 $";
 
 /*
  * Misc. lookup-tables.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_audio.h linux/drivers/isdn/isdn_audio.h
--- linux-2.4.16/drivers/isdn/isdn_audio.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_audio.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_audio.h,v 1.9.6.1 2001/09/23 22:24:31 kai Exp $
+/* $Id: isdn_audio.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- linux-2.4.16/drivers/isdn/isdn_common.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_common.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.114.6.16 2001/11/06 20:58:28 kai Exp $
+/* $Id: isdn_common.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -44,7 +44,7 @@
 
 isdn_dev *dev;
 
-static char *isdn_revision = "$Revision: 1.114.6.16 $";
+static char *isdn_revision = "$Revision: 1.1.4.1 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- linux-2.4.16/drivers/isdn/isdn_common.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_common.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.21.6.1 2001/09/23 22:24:31 kai Exp $
+/* $Id: isdn_common.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * header for Linux ISDN subsystem
  * common used functions and debugging-switches (linklevel).
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_concap.c linux/drivers/isdn/isdn_concap.c
--- linux-2.4.16/drivers/isdn/isdn_concap.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_concap.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_concap.c,v 1.8.6.1 2001/09/23 22:24:31 kai Exp $
+/* $Id: isdn_concap.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  * 
  * Linux ISDN subsystem, protocol encapsulation
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_concap.h linux/drivers/isdn/isdn_concap.h
--- linux-2.4.16/drivers/isdn/isdn_concap.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_concap.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_concap.h,v 1.3.6.1 2001/09/23 22:24:31 kai Exp $
+/* $Id: isdn_concap.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, protocol encapsulation
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- linux-2.4.16/drivers/isdn/isdn_net.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_net.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.140.6.11 2001/11/06 20:58:28 kai Exp $
+/* $Id: isdn_net.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -175,7 +175,7 @@
 static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
 static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
 
-char *isdn_net_revision = "$Revision: 1.140.6.11 $";
+char *isdn_net_revision = "$Revision: 1.1.4.1 $";
 
  /*
   * Code for raw-networking over ISDN
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h
--- linux-2.4.16/drivers/isdn/isdn_net.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_net.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.19.6.4 2001/09/28 08:05:29 kai Exp $
+/* $Id: isdn_net.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * header for Linux ISDN subsystem, network related functions (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- linux-2.4.16/drivers/isdn/isdn_ppp.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_ppp.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.85.6.9 2001/11/06 20:58:28 kai Exp $
+/* $Id: isdn_ppp.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -69,7 +69,7 @@
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
 #endif	/* CONFIG_ISDN_MPP */
   
-char *isdn_ppp_revision = "$Revision: 1.85.6.9 $";
+char *isdn_ppp_revision = "$Revision: 1.1.4.1 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h
--- linux-2.4.16/drivers/isdn/isdn_ppp.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_ppp.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.17.6.1 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_ppp.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- linux-2.4.16/drivers/isdn/isdn_tty.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_tty.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.94.6.9 2001/11/06 20:58:29 kai Exp $
+/* $Id: isdn_tty.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -53,7 +53,7 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.94.6.9 $";
+char *isdn_tty_revision = "$Revision: 1.1.4.1 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h
--- linux-2.4.16/drivers/isdn/isdn_tty.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_tty.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.22.6.2 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_tty.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * header for Linux ISDN subsystem, tty related functions (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_ttyfax.c linux/drivers/isdn/isdn_ttyfax.c
--- linux-2.4.16/drivers/isdn/isdn_ttyfax.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_ttyfax.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ttyfax.c,v 1.7.6.2 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_ttyfax.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
  *
@@ -20,7 +20,7 @@
 #include "isdn_ttyfax.h"
 
 
-static char *isdn_tty_fax_revision = "$Revision: 1.7.6.2 $";
+static char *isdn_tty_fax_revision = "$Revision: 1.1.4.1 $";
 
 #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_ttyfax.h linux/drivers/isdn/isdn_ttyfax.h
--- linux-2.4.16/drivers/isdn/isdn_ttyfax.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_ttyfax.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ttyfax.h,v 1.2.6.1 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_ttyfax.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c
--- linux-2.4.16/drivers/isdn/isdn_v110.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_v110.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.5.6.4 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_v110.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -19,7 +19,7 @@
 
 #undef ISDN_V110_DEBUG
 
-char *isdn_v110_revision = "$Revision: 1.5.6.4 $";
+char *isdn_v110_revision = "$Revision: 1.1.4.1 $";
 
 #define V110_38400 255
 #define V110_19200  15
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_v110.h linux/drivers/isdn/isdn_v110.h
--- linux-2.4.16/drivers/isdn/isdn_v110.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_v110.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_v110.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_x25iface.c linux/drivers/isdn/isdn_x25iface.c
--- linux-2.4.16/drivers/isdn/isdn_x25iface.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_x25iface.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_x25iface.c,v 1.9.6.1 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_x25iface.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * Linux ISDN subsystem, X.25 related functions
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdn_x25iface.h linux/drivers/isdn/isdn_x25iface.h
--- linux-2.4.16/drivers/isdn/isdn_x25iface.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdn_x25iface.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_x25iface.h,v 1.3.6.1 2001/09/23 22:24:32 kai Exp $
+/* $Id: isdn_x25iface.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
  *
  * header for Linux ISDN subsystem, x.25 related functions
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c
--- linux-2.4.16/drivers/isdn/isdnloop/isdnloop.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdnloop/isdnloop.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $
+/* $Id: isdnloop.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * ISDN low-level module implementing a dummy loop driver.
  *
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include "isdnloop.h"
 
-static char *revision = "$Revision: 1.11.6.7 $";
+static char *revision = "$Revision: 1.1.4.1 $";
 static char *isdnloop_id;
 
 MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h
--- linux-2.4.16/drivers/isdn/isdnloop/isdnloop.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/isdnloop/isdnloop.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $
+/* $Id: isdnloop.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Loopback lowlevel module for testing of linklevel.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/card.h linux/drivers/isdn/sc/card.h
--- linux-2.4.16/drivers/isdn/sc/card.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/card.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: card.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: card.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Driver parameters for SpellCaster ISA ISDN adapters
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/command.c linux/drivers/isdn/sc/command.c
--- linux-2.4.16/drivers/isdn/sc/command.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/command.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: command.c,v 1.4.10.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: command.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/debug.c linux/drivers/isdn/sc/debug.c
--- linux-2.4.16/drivers/isdn/sc/debug.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/debug.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: debug.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/debug.h linux/drivers/isdn/sc/debug.h
--- linux-2.4.16/drivers/isdn/sc/debug.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/debug.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: debug.h,v 1.2.8.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: debug.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/event.c linux/drivers/isdn/sc/event.c
--- linux-2.4.16/drivers/isdn/sc/event.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/event.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: event.c,v 1.4.8.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: event.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c
--- linux-2.4.16/drivers/isdn/sc/interrupt.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/interrupt.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: interrupt.c,v 1.4.8.3 2001/09/23 22:24:59 kai Exp $
+/* $Id: interrupt.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c
--- linux-2.4.16/drivers/isdn/sc/message.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/message.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: message.c,v 1.5.8.2 2001/09/23 22:24:59 kai Exp $
+/* $Id: message.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * functions for sending and receiving control messages
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/message.h linux/drivers/isdn/sc/message.h
--- linux-2.4.16/drivers/isdn/sc/message.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/message.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: message.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: message.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/packet.c linux/drivers/isdn/sc/packet.c
--- linux-2.4.16/drivers/isdn/sc/packet.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/packet.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: packet.c,v 1.5.8.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: packet.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/shmem.c linux/drivers/isdn/sc/shmem.c
--- linux-2.4.16/drivers/isdn/sc/shmem.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/shmem.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: shmem.c,v 1.2.10.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: shmem.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/sc/timer.c linux/drivers/isdn/sc/timer.c
--- linux-2.4.16/drivers/isdn/sc/timer.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/sc/timer.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: timer.c,v 1.3.6.1 2001/09/23 22:24:59 kai Exp $
+/* $Id: timer.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
  *
  * Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam.h linux/drivers/isdn/tpam/tpam.h
--- linux-2.4.16/drivers/isdn/tpam/tpam.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam.h	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam.h,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $
+/* $Id: tpam.h,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_commands.c linux/drivers/isdn/tpam/tpam_commands.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_commands.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_commands.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_commands.c,v 1.1.2.4 2001/11/06 20:58:30 kai Exp $
+/* $Id: tpam_commands.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_crcpc.c linux/drivers/isdn/tpam/tpam_crcpc.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_crcpc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_crcpc.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_crcpc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
+/* $Id: tpam_crcpc.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_hdlc.c linux/drivers/isdn/tpam/tpam_hdlc.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_hdlc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_hdlc.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_hdlc.c,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $
+/* $Id: tpam_hdlc.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver - HDLC encoding)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_main.c linux/drivers/isdn/tpam/tpam_main.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_main.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_main.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_main.c,v 1.1.2.3 2001/09/23 22:25:03 kai Exp $
+/* $Id: tpam_main.c,v 1.1.2.2 2001/12/09 18:45:14 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines)
  *
@@ -254,7 +254,7 @@
 	name:		"tpam",
 	id_table:	tpam_pci_tbl,
 	probe:		tpam_probe,
-	remove:		tpam_remove,
+	remove:		__devexit_p(tpam_remove),
 };
 
 static int __init tpam_init(void) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_memory.c linux/drivers/isdn/tpam/tpam_memory.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_memory.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_memory.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_memory.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
+/* $Id: tpam_memory.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver - Board Memory Access)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_nco.c linux/drivers/isdn/tpam/tpam_nco.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_nco.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_nco.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_nco.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
+/* $Id: tpam_nco.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. 
  * (Kernel Driver - Low Level NCO Manipulation)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/isdn/tpam/tpam_queues.c linux/drivers/isdn/tpam/tpam_queues.c
--- linux-2.4.16/drivers/isdn/tpam/tpam_queues.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/isdn/tpam/tpam_queues.c	Sun Dec  9 19:23:10 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam_queues.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
+/* $Id: tpam_queues.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/md/lvm-snap.c linux/drivers/md/lvm-snap.c
--- linux-2.4.16/drivers/md/lvm-snap.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/md/lvm-snap.c	Tue Dec  4 19:25:30 2001
@@ -542,8 +542,6 @@
 
 void lvm_snapshot_release(lv_t * lv)
 {
-	int 	nbhs = KIO_MAX_SECTORS;
-
 	if (lv->lv_block_exception)
 	{
 		vfree(lv->lv_block_exception);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/media/radio/radio-gemtek-pci.c linux/drivers/media/radio/radio-gemtek-pci.c
--- linux-2.4.16/drivers/media/radio/radio-gemtek-pci.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/media/radio/radio-gemtek-pci.c	Fri Dec  7 18:08:43 2001
@@ -424,7 +424,7 @@
     name:	"gemtek_pci",
 id_table:	gemtek_pci_id,
    probe:	gemtek_pci_probe,
-  remove:	gemtek_pci_remove
+  remove:	__devexit_p(gemtek_pci_remove),
 };
 
 static int __init gemtek_pci_init_module( void )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/media/radio/radio-maxiradio.c linux/drivers/media/radio/radio-maxiradio.c
--- linux-2.4.16/drivers/media/radio/radio-maxiradio.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/media/radio/radio-maxiradio.c	Fri Dec  7 18:08:43 2001
@@ -376,7 +376,7 @@
 	name:		"radio-maxiradio",
 	id_table:	maxiradio_pci_tbl,
 	probe:		maxiradio_init_one,
-	remove:		maxiradio_remove_one,
+	remove:		__devexit_p(maxiradio_remove_one),
 };
 
 int __init maxiradio_radio_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/media/video/Config.in linux/drivers/media/video/Config.in
--- linux-2.4.16/drivers/media/video/Config.in	Mon Nov 26 10:35:03 2001
+++ linux/drivers/media/video/Config.in	Tue Dec  4 19:25:30 2001
@@ -22,10 +22,8 @@
    fi
 fi
 if [ "$CONFIG_PARPORT" != "n" ]; then
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      if [ "$CONFIG_PARPORT_1284" != "n" ]; then
-         dep_tristate '  Winbond W9966CF Webcam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT
-      fi
+   if [ "$CONFIG_PARPORT_1284" != "n" ]; then
+      dep_tristate '  W9966CF Webcam (FlyCam Supra and others) Video For Linux' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT
    fi
 fi
 dep_tristate '  CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.4.16/drivers/media/video/bttv-driver.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/media/video/bttv-driver.c	Fri Dec  7 18:08:43 2001
@@ -3025,7 +3025,7 @@
         name:     "bttv",
         id_table: bttv_pci_tbl,
         probe:    bttv_probe,
-        remove:   bttv_remove,
+        remove:   __devexit_p(bttv_remove),
 };
 
 int bttv_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/media/video/meye.c linux/drivers/media/video/meye.c
--- linux-2.4.16/drivers/media/video/meye.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/media/video/meye.c	Fri Dec  7 18:08:43 2001
@@ -1460,7 +1460,7 @@
 	name:		"meye",
 	id_table:	meye_pci_tbl,
 	probe:		meye_probe,
-	remove:		meye_remove,
+	remove:		__devexit_p(meye_remove),
 };
 
 static int __init meye_init_module(void) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/media/video/w9966.c linux/drivers/media/video/w9966.c
--- linux-2.4.16/drivers/media/video/w9966.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/media/video/w9966.c	Tue Dec  4 19:25:30 2001
@@ -1,9 +1,7 @@
 /*
 	Winbond w9966cf Webcam parport driver.
 
-	Version 0.32
-
-	Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
+	Copyright (C) 2001 Jakob Kemi <jakob.kemi@telia.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
@@ -21,33 +19,16 @@
 */
 /*
 	Supported devices:
-	*Lifeview FlyCam Supra (using the Philips saa7111a chip)
-
-	Does any other model using the w9966 interface chip exist ?
+	  * Lifeview FlyCam Supra (using the Philips saa7111a chip)
 
 	Todo:
-	
-	*Add a working EPP mode, since DMA ECP read isn't implemented
-	in the parport drivers. (That's why it's so sloow)
-
-	*Add support for other ccd-control chips than the saa7111
-	please send me feedback on what kind of chips you have.
-
-	*Add proper probing. I don't know what's wrong with the IEEE1284
-	parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
-	and nibble read seems to be broken for some peripherals.
-
-	*Add probing for onboard SRAM, port directions etc. (if possible)
-
-	*Add support for the hardware compressed modes (maybe using v4l2)
-
-	*Fix better support for the capture window (no skewed images, v4l
-	interface to capt. window)
-
-	*Probably some bugs that I don't know of
+	  * Add a working EPP mode
+	  * Support other ccd-control chips than the saa7111
+	    (what combinations exists?)
+	  * Add proper probing. IEEE1284 probing of w9966 chips haven't
+	    worked since parport drivers changed in 2.4.x.
+	  * Probe for onboard SRAM, port directions etc. (if possible)
 
-	Please support me by sending feedback!
-	
 	Changes:
 	
 	Alan Cox:	Removed RGB mode for kernel merge, added THIS_MODULE
@@ -59,6 +40,8 @@
 #include <linux/delay.h>
 #include <linux/videodev.h>
 #include <linux/parport.h>
+#include <linux/types.h>
+#include <linux/slab.h>
 
 //#define DEBUG				// Undef me for production
 
@@ -99,43 +82,44 @@
 #define W9966_I2C_W_CLOCK	0x01
 
 struct w9966_dev {
-	unsigned char dev_state;
-	unsigned char i2c_state;
-	unsigned short ppmode;
+	u8 dev_state;
+	u8 i2c_state;
+	int ppmode;
 	struct parport* pport;
 	struct pardevice* pdev;
 	struct video_device vdev;
-	unsigned short width;
-	unsigned short height;
-	unsigned char brightness;
-	signed char contrast;
-	signed char color;
-	signed char hue;
+	u16 width;
+	u16 height;
+	u8 brightness;
+	s8 contrast;
+	s8 color;
+	s8 hue;
+	u8* buffer;
 };
 
 /*
  *	Module specific properties
  */
 
-MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
-MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
+MODULE_AUTHOR("Jakob Kemi <jakob.kemi@telia.com>");
+MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)");
 MODULE_LICENSE("GPL");
 
 
-#ifdef MODULE
-static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
-#else
-static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
-#endif
-MODULE_PARM(pardev, "1-" __MODULE_STRING(W9966_MAXCAMS) "s");
-MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
-\teach camera. 'aggressive' means brute-force search.\n\
-\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign
-\tcam 1 to parport3 and search every parport for cam 2 etc...");
+static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"};
+MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s");
+MODULE_PARM_DESC(pardev,"\n\
+<auto|name|none[,...]> Where to find cameras.\n\
+  auto = probe all parports for camera\n\
+  name = name of parport (eg parport0)\n\
+  none = don't search for this camera\n\
+You can specify all cameras this way, for example:
+  pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\
+  for cam2 on all parports, skip cam3 and search for cam4 on parport0");
 
 static int parmode = 0;
 MODULE_PARM(parmode, "i");
-MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
+MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)");
 
 static int video_nr = -1;
 MODULE_PARM(video_nr, "i");
@@ -277,17 +261,23 @@
 	case 0:
 		if (port->modes & PARPORT_MODE_ECP)
 			cam->ppmode = IEEE1284_MODE_ECP;
-		else if (port->modes & PARPORT_MODE_EPP)
-			cam->ppmode = IEEE1284_MODE_EPP;
+/*		else if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;*/
 		else
-			cam->ppmode = IEEE1284_MODE_ECP;
+			cam->ppmode = IEEE1284_MODE_ECPSWE;
 		break;	
 	case 1:		// hw- or sw-ecp
-		cam->ppmode = IEEE1284_MODE_ECP;
+		if (port->modes & PARPORT_MODE_ECP)
+			cam->ppmode = IEEE1284_MODE_ECP;
+		else
+			cam->ppmode = IEEE1284_MODE_ECPSWE;
 		break;
 	case 2:		// hw- or sw-epp
-		cam->ppmode = IEEE1284_MODE_EPP;
-	break;
+		if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;
+		else
+			cam->ppmode = IEEE1284_MODE_EPPSWE;
+		break;
 	}
 	
 // Tell the parport driver that we exists
@@ -325,6 +315,8 @@
 	
 	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
 	
+	cam->buffer = NULL;
+	
 	// All ok
 	printk(
 		"w9966cf: Found and initialized a webcam on %s.\n",
@@ -337,6 +329,12 @@
 // Terminate everything gracefully
 static void w9966_term(struct w9966_dev* cam)
 {
+// Delete allocated buffer if needed
+	if (cam->buffer != NULL) {
+		kfree(cam->buffer);
+		cam->buffer = NULL;
+	}
+
 // Unregister from v4l
 	if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
 		video_unregister_device(&cam->vdev);
@@ -431,9 +429,9 @@
 {
 	unsigned int i;
 	unsigned int enh_s, enh_e;
-	unsigned char scale_x, scale_y;
-	unsigned char regs[0x1c];
-	unsigned char saa7111_regs[] = {
+	u8 scale_x, scale_y;
+	u8 regs[0x1c];
+	u8 saa7111_regs[] = {
 		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
 		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
 		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -664,6 +662,7 @@
 	return data;
 }
 
+
 // Write a register to the i2c device.
 // Expects claimed pdev. -1 on error
 static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
@@ -693,11 +692,23 @@
 
 static int w9966_v4l_open(struct video_device *vdev, int flags)
 {
+	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
+	cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL);
+	
+	if (cam->buffer == NULL)
+		return -EFAULT;
+
 	return 0;
 }
 
 static void w9966_v4l_close(struct video_device *vdev)
 {
+	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
+	
+	if (cam->buffer != NULL) {
+		kfree(cam->buffer);
+		cam->buffer = NULL;
+	}
 }
 
 static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
@@ -920,13 +931,12 @@
 	while(dleft > 0)
 	{
 		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
-		unsigned char tbuf[W9966_RBUFFER];
 	
-		if (parport_read(cam->pport, tbuf, tsize) < tsize) {
+		if (parport_read(cam->pport, cam->buffer, tsize) < tsize) {
 			w9966_pdev_release(cam);
 			return -EFAULT;
 		}
-		if (copy_to_user(dest, tbuf, tsize) != 0) {
+		if (copy_to_user(dest, cam->buffer, tsize) != 0) {
 			w9966_pdev_release(cam);
 			return -EFAULT;
 		}
@@ -948,14 +958,14 @@
 	
 	for (i = 0; i < W9966_MAXCAMS; i++)
 	{
+		if (strcmp(pardev[i], "none") == 0)	// Skip if 'none'
+			continue;
 		if (w9966_cams[i].dev_state != 0)	// Cam is already assigned
 			continue;
-		if (
-			strcmp(pardev[i], "aggressive") == 0 ||
-			strcmp(pardev[i], port->name) == 0
-		) {
+		if (strcmp(pardev[i], "auto") == 0 ||
+		    strcmp(pardev[i], port->name) == 0) {
 			if (w9966_init(&w9966_cams[i], port) != 0)
-			w9966_term(&w9966_cams[i]);
+				w9966_term(&w9966_cams[i]);
 			break;	// return
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- linux-2.4.16/drivers/net/3c59x.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/3c59x.c	Fri Dec  7 18:08:43 2001
@@ -2919,7 +2919,7 @@
 static struct pci_driver vortex_driver = {
 	name:		"3c59x",
 	probe:		vortex_init_one,
-	remove:		vortex_remove_one,
+	remove:		__devexit_p(vortex_remove_one),
 	id_table:	vortex_pci_tbl,
 #ifdef CONFIG_PM
 	suspend:	vortex_suspend,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/8139cp.c linux/drivers/net/8139cp.c
--- linux-2.4.16/drivers/net/8139cp.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/8139cp.c	Fri Dec  7 18:08:43 2001
@@ -1313,7 +1313,7 @@
 	name:		DRV_NAME,
 	id_table:	cp_pci_tbl,
 	probe:		cp_init_one,
-	remove:		cp_remove_one,
+	remove:		__devexit_p(cp_remove_one),
 };
 
 static int __init cp_init (void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/8139too.c linux/drivers/net/8139too.c
--- linux-2.4.16/drivers/net/8139too.c	Mon Nov 26 10:35:11 2001
+++ linux/drivers/net/8139too.c	Fri Dec  7 18:08:43 2001
@@ -1636,23 +1636,24 @@
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	unsigned int entry;
+	unsigned int len = skb->len;
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = tp->cur_tx % NUM_TX_DESC;
 
-	if (likely(skb->len < TX_BUF_SIZE)) {
+	if (likely(len < TX_BUF_SIZE)) {
 		skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
 		dev_kfree_skb(skb);
 	} else {
 		dev_kfree_skb(skb);
 		tp->stats.tx_dropped++;
 		return 0;
-  	}
+	}
 
 	/* Note: the chip doesn't have auto-pad! */
 	spin_lock_irq(&tp->lock);
 	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
-		   tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
 
 	dev->trans_start = jiffies;
 
@@ -1663,8 +1664,8 @@
 		netif_stop_queue (dev);
 	spin_unlock_irq(&tp->lock);
 
-	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
-		 dev->name, skb->data, skb->len, entry);
+	DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n",
+		 dev->name, len, entry);
 
 	return 0;
 }
@@ -2493,7 +2494,7 @@
 	name:		DRV_NAME,
 	id_table:	rtl8139_pci_tbl,
 	probe:		rtl8139_init_one,
-	remove:		rtl8139_remove_one,
+	remove:		__devexit_p(rtl8139_remove_one),
 #ifdef CONFIG_PM
 	suspend:	rtl8139_suspend,
 	resume:		rtl8139_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.4.16/drivers/net/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/Config.in	Wed Dec  5 16:36:05 2001
@@ -10,9 +10,7 @@
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   if [ "$CONFIG_NETLINK" = "y" ]; then
-      tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
-   fi
+   tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
 fi
 
 if [ "$CONFIG_ISAPNP" = "y" -o "$CONFIG_ISAPNP" = "m" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c
--- linux-2.4.16/drivers/net/arcnet/com20020-pci.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/arcnet/com20020-pci.c	Fri Dec  7 18:08:43 2001
@@ -160,7 +160,7 @@
 	name:		"com20020",
 	id_table:	com20020pci_id_table,
 	probe:		com20020pci_probe,
-	remove:		com20020pci_remove
+	remove:		__devexit_p(com20020pci_remove),
 };
 
 static int __init com20020pci_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/bonding.c linux/drivers/net/bonding.c
--- linux-2.4.16/drivers/net/bonding.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/bonding.c	Tue Dec  4 19:25:30 2001
@@ -185,7 +185,6 @@
 
 #include <linux/if_bonding.h>
 #include <linux/smp.h>
-#include <limits.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/defxx.c linux/drivers/net/defxx.c
--- linux-2.4.16/drivers/net/defxx.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/defxx.c	Fri Dec  7 18:08:43 2001
@@ -3360,7 +3360,7 @@
 static struct pci_driver dfx_driver = {
 	name:		"defxx",
 	probe:		dfx_init_one,
-	remove:		dfx_remove_one,
+	remove:		__devexit_p(dfx_remove_one),
 	id_table:	dfx_pci_tbl,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/dl2k.c linux/drivers/net/dl2k.c
--- linux-2.4.16/drivers/net/dl2k.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/dl2k.c	Fri Dec  7 18:08:43 2001
@@ -1671,7 +1671,7 @@
 	name:"dl2k",
 	id_table:rio_pci_tbl,
 	probe:rio_probe1,
-	remove:rio_remove1,
+	remove:__devexit_p(rio_remove1),
 };
 
 static int __init
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- linux-2.4.16/drivers/net/eepro100.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/eepro100.c	Fri Dec  7 18:08:43 2001
@@ -2273,6 +2273,22 @@
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_7,
 		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 	0x1032,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 0x1033,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 0x1034,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 0x1038,
+		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, 	0x5200,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 	0x5201,
+		PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0,}
 };
 MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
@@ -2281,7 +2297,7 @@
 	name:		"eepro100",
 	id_table:	eepro100_pci_tbl,
 	probe:		eepro100_init_one,
-	remove:		eepro100_remove_one,
+	remove:		__devexit_p(eepro100_remove_one),
 #ifdef CONFIG_PM
 	suspend:	eepro100_suspend,
 	resume:		eepro100_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/epic100.c linux/drivers/net/epic100.c
--- linux-2.4.16/drivers/net/epic100.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/epic100.c	Fri Dec  7 18:08:43 2001
@@ -1507,7 +1507,7 @@
 	name:		DRV_NAME,
 	id_table:	epic_pci_tbl,
 	probe:		epic_init_one,
-	remove:		epic_remove_one,
+	remove:		__devexit_p(epic_remove_one),
 #ifdef CONFIG_PM
 	suspend:	epic_suspend,
 	resume:		epic_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/fealnx.c linux/drivers/net/fealnx.c
--- linux-2.4.16/drivers/net/fealnx.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/fealnx.c	Fri Dec  7 18:08:43 2001
@@ -1858,7 +1858,7 @@
 	name:		"fealnx",
 	id_table:	fealnx_pci_tbl,
 	probe:		fealnx_init_one,
-	remove:		fealnx_remove_one,
+	remove:		__devexit_p(fealnx_remove_one),
 };
 
 static int __init fealnx_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
--- linux-2.4.16/drivers/net/ioc3-eth.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/ioc3-eth.c	Fri Dec  7 18:08:43 2001
@@ -1515,7 +1515,7 @@
 	name:		"ioc3-eth",
 	id_table:	ioc3_pci_tbl,
 	probe:		ioc3_probe,
-	remove:		ioc3_remove_one,
+	remove:		__devexit_p(ioc3_remove_one),
 };
 
 static int __init ioc3_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/irda/vlsi_ir.c linux/drivers/net/irda/vlsi_ir.c
--- linux-2.4.16/drivers/net/irda/vlsi_ir.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/irda/vlsi_ir.c	Fri Dec  7 18:08:43 2001
@@ -2,7 +2,7 @@
  *
  *	vlsi_ir.c:	VLSI82C147 PCI IrDA controller driver for Linux
  *
- *	Version:	0.3, Sep 30, 2001
+ *	Version:	0.3a, Nov 10, 2001
  *
  *	Copyright (c) 2001 Martin Diehl
  *
@@ -490,7 +490,7 @@
 	if (mode == IFF_FIR)
 		config ^= IRENABLE_FIR_ON;
 	else if (mode == IFF_MIR)
-		config ^= (IRENABLE_FIR_ON|IRENABLE_CRC16_ON);
+		config ^= (IRENABLE_MIR_ON|IRENABLE_CRC16_ON);
 	else
 		config ^= IRENABLE_SIR_ON;
 
@@ -877,6 +877,7 @@
 	idev->irlap = irlap_open(ndev,&idev->qos,hwname);
 
 	netif_start_queue(ndev);
+	outw(0, ndev->base_addr+VLSI_PIO_PROMPT);	/* kick hw state machine */
 
 	printk(KERN_INFO "%s: device %s operational using (%d,%d) tx,rx-ring\n",
 		__FUNCTION__, ndev->name, ringsize[0], ringsize[1]);
@@ -1200,7 +1201,6 @@
 	int			alloc_size;
 
 
-	vlsi_reg_debug(0x3000, "vlsi initial state");
 	if (pci_enable_device(pdev))
 		goto out;
 
@@ -1291,7 +1291,7 @@
 	name:           drivername,
 	id_table:       vlsi_irda_table,
 	probe:          vlsi_irda_probe,
-	remove:         vlsi_irda_remove,
+	remove:         __devexit_p(vlsi_irda_remove),
 	suspend:        vlsi_irda_suspend,
 	resume:         vlsi_irda_resume,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- linux-2.4.16/drivers/net/natsemi.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/natsemi.c	Fri Dec  7 18:08:43 2001
@@ -2518,7 +2518,7 @@
 	name:		DRV_NAME,
 	id_table:	natsemi_pci_tbl,
 	probe:		natsemi_probe1,
-	remove:		natsemi_remove1,
+	remove:		__devexit_p(natsemi_remove1),
 #ifdef CONFIG_PM
 	suspend:	natsemi_suspend,
 	resume:		natsemi_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- linux-2.4.16/drivers/net/ne2k-pci.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/ne2k-pci.c	Fri Dec  7 18:08:43 2001
@@ -642,7 +642,7 @@
 static struct pci_driver ne2k_driver = {
 	name:		DRV_NAME,
 	probe:		ne2k_pci_init_one,
-	remove:		ne2k_pci_remove_one,
+	remove:		__devexit_p(ne2k_pci_remove_one),
 	id_table:	ne2k_pci_tbl,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/ns83820.c linux/drivers/net/ns83820.c
--- linux-2.4.16/drivers/net/ns83820.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/ns83820.c	Sun Dec  9 22:57:53 2001
@@ -1,7 +1,7 @@
-#define VERSION "0.13"
-/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com>
+#define _VERSION "0.15"
+/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> with contributions.
  *
- * $Revision: 1.34.2.8 $
+ * $Revision: 1.34.2.12 $
  *
  * Copyright 2001 Benjamin LaHaise.
  * Copyright 2001 Red Hat.
@@ -45,6 +45,12 @@
  *			0.12 - add statistics counters
  *			     - add allmulti/promisc support
  *	20011009	0.13 - hotplug support, other smaller pci api cleanups
+ *	20011204	0.13a - optical transceiver support added
+ *				by Michael Clark <michael@metaparadigm.com>
+ *	20011205	0.13b - call register_netdev earlier in initialization
+ *				suppress duplicate link status messages
+ *	20011117 	0.14 - ethtool GDRVINFO, GLINK support from jgarzik
+ *	20011204 	0.15	get ppc (big endian) working
  *
  * Driver Overview
  * ===============
@@ -65,6 +71,7 @@
  *	D-Link		DGE-500T
  *	PureData	PDP8023Z-TG
  *	SMC		SMC9452TX	SMC9462TX
+ *	Netgear		GA621
  *
  * Special thanks to SMC for providing hardware to test this driver on.
  *
@@ -86,23 +93,25 @@
 #include <linux/in.h>	/* for IPPROTO_... */
 #include <linux/eeprom.h>
 #include <linux/compiler.h>
+#include <linux/ethtool.h>
 //#include <linux/skbrefill.h>
 
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 /* Dprintk is used for more interesting debug events */
 #undef Dprintk
 #define	Dprintk			dprintk
 
 #ifdef CONFIG_HIGHMEM64G
-#define USE_64BIT_ADDR
+#define USE_64BIT_ADDR	"+"
 #elif defined(__ia64__)
-#define USE_64BIT_ADDR
+#define USE_64BIT_ADDR	"+"
 #endif
 
 /* Tell davem to fix the pci dma api.  Grrr. */
 /* stolen from acenic.c */
-#ifdef CONFIG_HIGHMEM
+#if 0 //def CONFIG_HIGHMEM
 #if defined(CONFIG_X86)
 #define DMAADDR_OFFSET  0
 #if defined(CONFIG_HIGHMEM64G)
@@ -138,6 +147,12 @@
 }
 #endif
 
+#if defined(USE_64BIT_ADDR)
+#define	VERSION	_VERSION USE_64BIT_ADDR
+#else
+#define	VERSION	_VERSION
+#endif
+
 /* tunables */
 #define RX_BUF_SIZE	6144	/* 8192 */
 #define NR_RX_DESC	256
@@ -213,6 +228,7 @@
 #define CFG_DUPSTS	0x10000000
 #define CFG_TBI_EN	0x01000000
 #define CFG_MODE_1000	0x00400000
+#define CFG_AUTO_1000	0x00200000
 #define CFG_PINT_CTL	0x001c0000
 #define CFG_PINT_DUPSTS	0x00100000
 #define CFG_PINT_LNKSTS	0x00080000
@@ -316,6 +332,36 @@
 #define VDR		0xc4
 #define CCSR		0xcc
 
+#define TBICR		0xe0
+#define TBISR		0xe4
+#define TANAR		0xe8
+#define TANLPAR		0xec
+#define TANER		0xf0
+#define TESR		0xf4
+
+#define TBICR_MR_AN_ENABLE	0x00001000
+#define TBICR_MR_RESTART_AN	0x00000200
+
+#define TBISR_MR_LINK_STATUS	0x00000020
+#define TBISR_MR_AN_COMPLETE	0x00000004
+
+#define TANAR_PS2 		0x00000100
+#define TANAR_PS1 		0x00000080
+#define TANAR_HALF_DUP 		0x00000040
+#define TANAR_FULL_DUP 		0x00000020
+
+#define GPIOR_GP5_OE		0x00000200
+#define GPIOR_GP4_OE		0x00000100
+#define GPIOR_GP3_OE		0x00000080
+#define GPIOR_GP2_OE		0x00000040
+#define GPIOR_GP1_OE		0x00000020
+#define GPIOR_GP3_OUT		0x00000004
+#define GPIOR_GP1_OUT		0x00000001
+
+#define LINK_AUTONEGOTIATE	0x01
+#define LINK_DOWN		0x02
+#define LINK_UP			0x04
+
 #define __kick_rx(dev)	writel(CR_RXE, dev->base + CR)
 
 #define kick_rx(dev) do { \
@@ -390,6 +436,7 @@
 	u32			IMR_cache;
 	struct eeprom		ee;
 
+	unsigned		linkstate;
 
 	spinlock_t	tx_lock;
 
@@ -441,11 +488,11 @@
 
 static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts)
 {
-	desc[0] = link;
-	desc[1] = buf;
-	desc[3] = extsts;
+	desc[0] = cpu_to_le32(link);
+	desc[1] = cpu_to_le32(buf);
+	desc[3] = cpu_to_le32(extsts);
 	mb();
-	desc[2] = cmdsts;
+	desc[2] = cpu_to_le32(cmdsts);
 }
 
 #define build_rx_desc	build_rx_desc32
@@ -486,7 +533,7 @@
 	build_rx_desc(dev, sg, 0, buf, cmdsts, 0);
 	/* update link of previous rx */
 	if (next_empty != dev->rx_info.next_rx)
-		dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4);
+		dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = cpu_to_le32(dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4));
 
 	return 0;
 }
@@ -545,39 +592,93 @@
 
 static void phy_intr(struct ns83820 *dev)
 {
-	static char *speeds[] = { "10", "100", "1000", "1000(?)" };
+	static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
 	u32 cfg, new_cfg;
+	u32 tbisr, tanar, tanlpar;
+	int speed, fullduplex, newlinkstate;
 
-	new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
 	cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
 
-	if (cfg & CFG_SPDSTS1)
-		new_cfg |= CFG_MODE_1000 | CFG_SB;
-	else
-		new_cfg &= ~CFG_MODE_1000 | CFG_SB;
+	if (dev->CFG_cache & CFG_TBI_EN) {
 
-	if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
-		writel(new_cfg, dev->base + CFG);
-		dev->CFG_cache = new_cfg;
-	}
+		/* we have an optical transceiver */
+		tbisr = readl(dev->base + TBISR);
+		tanar = readl(dev->base + TANAR);
+		tanlpar = readl(dev->base + TANLPAR);
+		dprintk("phy_intr: tbisr=%08x, tanar=%08x, tanlpar=%08x\n",
+			tbisr, tanar, tanlpar);
+
+		if ( (fullduplex = (tanlpar & TANAR_FULL_DUP)
+		      && (tanar & TANAR_FULL_DUP)) ) {
+
+			/* both of us are full duplex */
+			writel(readl(dev->base + TXCFG)
+			       | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+			       dev->base + TXCFG);
+			writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+			       dev->base + RXCFG);
+			/* Light up full duplex LED */
+			writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
+			       dev->base + GPIOR);
+
+		} else if(((tanlpar & TANAR_HALF_DUP)
+			   && (tanar & TANAR_HALF_DUP))
+			|| ((tanlpar & TANAR_FULL_DUP)
+			    && (tanar & TANAR_HALF_DUP))
+			|| ((tanlpar & TANAR_HALF_DUP)
+			    && (tanar & TANAR_FULL_DUP))) {
+
+			/* one or both of us are half duplex */
+			writel((readl(dev->base + TXCFG)
+				& ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP,
+			       dev->base + TXCFG);
+			writel(readl(dev->base + RXCFG) & ~RXCFG_RX_FD,
+			       dev->base + RXCFG);
+			/* Turn off full duplex LED */
+			writel(readl(dev->base + GPIOR) & ~GPIOR_GP1_OUT,
+			       dev->base + GPIOR);
+		}
 
-	dev->CFG_cache &= ~CFG_SPDSTS;
-	dev->CFG_cache |= cfg & CFG_SPDSTS;
+		speed = 4; /* 1000F */
 
-	if (cfg & CFG_LNKSTS) {
-		netif_start_queue(&dev->net_dev);
-		netif_wake_queue(&dev->net_dev);
 	} else {
-		netif_stop_queue(&dev->net_dev);
+		/* we have a copper transceiver */
+		new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
+
+		if (cfg & CFG_SPDSTS1)
+			new_cfg |= CFG_MODE_1000 | CFG_SB;
+		else
+			new_cfg &= ~CFG_MODE_1000 | CFG_SB;
+
+		if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
+			writel(new_cfg, dev->base + CFG);
+			dev->CFG_cache = new_cfg;
+		}
+
+		dev->CFG_cache &= ~CFG_SPDSTS;
+		dev->CFG_cache |= cfg & CFG_SPDSTS;
+
+		speed = ((cfg / CFG_SPDSTS0) & 3);
+		fullduplex = (cfg & CFG_DUPSTS);
 	}
 
-	if (cfg & CFG_LNKSTS)
+	newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN;
+
+	if (newlinkstate & LINK_UP
+	    && dev->linkstate != newlinkstate) {
+		netif_start_queue(&dev->net_dev);
+		netif_wake_queue(&dev->net_dev);
 		printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n",
 			dev->net_dev.name,
-			speeds[((cfg / CFG_SPDSTS0) & 3)],
-			(cfg & CFG_DUPSTS) ? "full" : "half");
-	else
+			speeds[speed],
+			fullduplex ? "full" : "half");
+	} else if (newlinkstate & LINK_DOWN
+		   && dev->linkstate != newlinkstate) {
+		netif_stop_queue(&dev->net_dev);
 		printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name);
+	}
+
+	dev->linkstate = newlinkstate;
 }
 
 static int ns83820_setup_rx(struct ns83820 *dev)
@@ -698,15 +799,15 @@
 	dprintk("walking descs\n");
 	next_rx = info->next_rx;
 	desc = info->descs + (DESC_SIZE * next_rx);
-	while ((CMDSTS_OWN & (cmdsts = desc[CMDSTS])) &&
+	while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) &&
 	       (cmdsts != CMDSTS_OWN)) {
 		struct sk_buff *skb;
-		u32 extsts = desc[EXTSTS];
-		dmaaddr_high_t bufptr = *(hw_addr_t *)(desc + BUFPTR);
+		u32 extsts = le32_to_cpu(desc[EXTSTS]);
+		dmaaddr_high_t bufptr = le32_to_cpu(desc[BUFPTR]);
 
 		dprintk("cmdsts: %08x\n", cmdsts);
-		dprintk("link: %08x\n", desc[LINK]);
-		dprintk("extsts: %08x\n", desc[EXTSTS]);
+		dprintk("link: %08x\n", cpu_to_le32(desc[LINK]));
+		dprintk("extsts: %08x\n", extsts);
 
 		skb = info->skbs[next_rx];
 		info->skbs[next_rx] = NULL;
@@ -718,14 +819,14 @@
 		pci_unmap_single(dev->pci_dev, bufptr,
 				 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
 		if (CMDSTS_OK & cmdsts) {
-#ifndef __i386__
+#if 0 //ndef __i386__
 			struct sk_buff *tmp;
 #endif
 			int len = cmdsts & 0xffff;
 			if (!skb)
 				BUG();
 			skb_put(skb, len);
-#ifndef __i386__	/* I hate the network stack sometimes */
+#if 0 //ndef __i386__	/* I hate the network stack sometimes */
 			tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC);
 			if (!tmp)
 				goto done;
@@ -788,9 +889,9 @@
 	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 
 	dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
-		tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[CMDSTS]));
 	while ((tx_done_idx != dev->tx_free_idx) &&
-	       !(CMDSTS_OWN & (cmdsts = desc[CMDSTS])) ) {
+	       !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) {
 		struct sk_buff *skb;
 
 		if (cmdsts & CMDSTS_ERR)
@@ -801,13 +902,13 @@
 			dev->stats.tx_bytes += cmdsts & 0xffff;
 
 		dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
-			tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
+			tx_done_idx, dev->tx_free_idx, cmdsts);
 		skb = dev->tx_skbs[tx_done_idx];
 		dev->tx_skbs[tx_done_idx] = NULL;
 		dprintk("done(%p)\n", skb);
 		if (skb) {
 			pci_unmap_single(dev->pci_dev,
-					*(hw_addr_t *)(desc + BUFPTR),
+					le32_to_cpu(desc[BUFPTR]),
 					skb->len,
 					PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(skb);
@@ -815,7 +916,7 @@
 
 		tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
 		dev->tx_done_idx = tx_done_idx;
-		desc[CMDSTS] = 0;
+		desc[CMDSTS] = cpu_to_le32(0);
 		barrier();
 		desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 	}
@@ -936,17 +1037,17 @@
 		}
 #endif
 
-		dprintk("frag[%3u]: %4u @ 0x%x%08Lx\n", free_idx, len,
+		dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
 			(unsigned long long)buf);
 		free_idx = (free_idx + 1) % NR_TX_DESC;
-		desc[LINK] = dev->tx_phy_descs + (free_idx * DESC_SIZE * 4);
-		*(hw_addr_t *)(desc + BUFPTR) = buf;
-		desc[EXTSTS] = extsts;
+		desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
+		desc[BUFPTR] = cpu_to_le32(buf);
+		desc[EXTSTS] = cpu_to_le32(extsts);
 
 		cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
 		cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
 		cmdsts |= len;
-		desc[CMDSTS] = cmdsts;
+		desc[CMDSTS] = cpu_to_le32(cmdsts);
 
 		if (residue) {
 			buf += len;
@@ -967,7 +1068,7 @@
 	}
 	dprintk("done pkt\n");
 	dev->tx_skbs[free_idx] = skb;
-	first_desc[CMDSTS] |= CMDSTS_OWN;
+	first_desc[CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
 	dev->tx_free_idx = free_idx;
 	kick_tx(dev);
 
@@ -1007,6 +1108,59 @@
 	return &dev->stats;
 }
 
+static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr)
+{
+	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, "ns83820");
+			strcpy(info.version, VERSION);
+			strcpy(info.bus_info, dev->pci_dev->slot_name);
+			if (copy_to_user(useraddr, &info, sizeof (info)))
+				return -EFAULT;
+			return 0;
+		}
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+
+		if (cfg & CFG_LNKSTS)
+			edata.data = 1;
+		else
+			edata.data = 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd)
+{
+	struct ns83820 *dev = _dev->priv;
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return ns83820_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct ns83820 *dev = data;
@@ -1048,10 +1202,14 @@
 			Dprintk("BAD\n");
 	}
 
-	if (ISR_RXSOVR & isr)
-		Dprintk("overrun\n");
-	if (ISR_RXORN & isr)
-		Dprintk("overrun\n");
+	if (unlikely(ISR_RXSOVR & isr)) {
+		Dprintk("overrun: rxsovr\n");
+		dev->stats.rx_over_errors ++;
+	}
+	if (unlikely(ISR_RXORN & isr)) {
+		Dprintk("overrun: rxorn\n");
+		dev->stats.rx_over_errors ++;
+	}
 
 	if ((ISR_RXRCMP & isr) && dev->rx_info.up)
 		writel(CR_RXE, dev->base + CR);
@@ -1150,9 +1308,10 @@
 
 	memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);
 	for (i=0; i<NR_TX_DESC; i++) {
-		*(hw_addr_t *)(dev->tx_descs + (i * DESC_SIZE) + LINK)
-				= dev->tx_phy_descs
-				  + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4;
+		dev->tx_descs[(i * DESC_SIZE) + LINK]
+				= cpu_to_le32(
+				  dev->tx_phy_descs
+				  + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4);
 	}
 
 	dev->tx_idx = 0;
@@ -1190,6 +1349,9 @@
 #if 0	/* I've left this in as an example of how to use eeprom.h */
 		data = eeprom_readw(&dev->ee, 0xa + 2 - i);
 #else
+		/* Read from the perfect match memory: this is loaded by
+		 * the chip from the EEPROM via the EELOAD self test.
+		 */
 		writel(i*2, dev->base + RFCR);
 		data = readl(dev->base + RFDR);
 #endif
@@ -1287,6 +1449,8 @@
 		goto out_unmap;
 	}
 
+	if(register_netdev(&dev->net_dev)) goto out_unmap;
+
 	dev->net_dev.open = ns83820_open;
 	dev->net_dev.stop = ns83820_stop;
 	dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
@@ -1294,6 +1458,7 @@
 	dev->net_dev.get_stats = ns83820_get_stats;
 	dev->net_dev.change_mtu = ns83820_change_mtu;
 	dev->net_dev.set_multicast_list = ns83820_set_multicast;
+	dev->net_dev.do_ioctl = ns83820_ioctl;
 	//FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout;
 
 	pci_set_drvdata(pci_dev, dev);
@@ -1318,12 +1483,15 @@
 	dev->CFG_cache = readl(dev->base + CFG);
 
 	if ((dev->CFG_cache & CFG_PCI64_DET)) {
-		printk("%s: enabling 64 bit PCI.\n", dev->net_dev.name);
+		printk("%s: enabling 64 bit PCI addressing.\n",
+			dev->net_dev.name);
 		dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN;
-	} else {
-		printk("%s: disabling 64 bit PCI.\n", dev->net_dev.name);
+#if defined(USE_64BIT_ADDR)
+		dev->net_dev.features |= NETIF_F_HIGHDMA;
+#endif
+	} else
 		dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN);
-	}
+
 	dev->CFG_cache &= (CFG_TBI_EN  | CFG_MRM_DIS   | CFG_MWI_DIS |
 			   CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 |
 			   CFG_M64ADDR);
@@ -1333,15 +1501,28 @@
 	dev->CFG_cache |= CFG_POW;
 #ifdef USE_64BIT_ADDR
 	dev->CFG_cache |= CFG_M64ADDR;
-	printk("using 64 bit addressing\n");
 #endif
-#ifdef __LITTLE_ENDIAN
+	/* Big endian mode does not seem to do what the docs suggest */
 	dev->CFG_cache &= ~CFG_BEM;
-#elif defined(__BIG_ENDIAN)
-	dev->CFG_cache |= CFG_BEM;
-#else
-#error This driver only works for big or little endian!!!
-#endif
+
+	/* setup optical transceiver if we have one */
+	if (dev->CFG_cache & CFG_TBI_EN) {
+		printk("%s: enabling optical transceiver\n", dev->net_dev.name);
+		writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
+
+		/* setup auto negotiation feature advertisement */
+		writel(readl(dev->base + TANAR)
+		       | TANAR_HALF_DUP | TANAR_FULL_DUP,
+		       dev->base + TANAR);
+
+		/* start auto negotiation */
+		writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+		       dev->base + TBICR);
+		writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
+		dev->linkstate = LINK_AUTONEGOTIATE;
+
+		dev->CFG_cache |= CFG_MODE_1000;
+	}
 
 	writel(dev->CFG_cache, dev->base + CFG);
 	dprintk("CFG: %08x\n", dev->CFG_cache);
@@ -1397,15 +1578,15 @@
 	dev->net_dev.features |= NETIF_F_HIGHDMA;
 #endif
 
-	register_netdev(&dev->net_dev);
-
-	printk(KERN_INFO "%s: ns83820.c v" VERSION ": DP83820 %02x:%02x:%02x:%02x:%02x:%02x pciaddr=0x%08lx irq=%d rev 0x%x\n",
+	printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n",
 		dev->net_dev.name,
+		(unsigned)readl(dev->base + SRR) >> 8,
+		(unsigned)readl(dev->base + SRR) & 0xff,
 		dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1],
 		dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3],
 		dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5],
 		addr, pci_dev->irq,
-		(unsigned)readl(dev->base + SRR)
+		(dev->net_dev.features & NETIF_F_HIGHDMA) ? "sg" : "h,sg"
 		);
 
 	return 0;
@@ -1455,7 +1636,7 @@
 	name:		"ns83820",
 	id_table:	ns83820_pci_tbl,
 	probe:		ns83820_init_one,
-	remove:		ns83820_remove_one,
+	remove:		__devexit_p(ns83820_remove_one),
 #if 0	/* FIXME: implement */
 	suspend:	,
 	resume:		,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c
--- linux-2.4.16/drivers/net/pci-skeleton.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pci-skeleton.c	Mon Dec 10 18:45:24 2001
@@ -834,7 +834,7 @@
 		printk (KERN_INFO
 			"%s: Media type forced to Full Duplex.\n",
 			dev->name);
-		mdio_write (dev, tp->phys[0], 4, 0x141);
+		mdio_write (dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
 		tp->duplex_lock = 1;
 	}
 
@@ -1235,20 +1235,20 @@
 	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int next_tick = 60 * HZ;
-	int mii_reg5;
+	int mii_lpa;
 
-	mii_reg5 = mdio_read (dev, tp->phys[0], 5);
+	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
 
-	if (!tp->duplex_lock && mii_reg5 != 0xffff) {
-		int duplex = (mii_reg5 & 0x0100)
-		    || (mii_reg5 & 0x01C0) == 0x0040;
+	if (!tp->duplex_lock && mii_lpa != 0xffff) {
+		int duplex = (mii_lpa & LPA_100FULL)
+		    || (mii_lpa & 0x01C0) == 0x0040;
 		if (tp->full_duplex != duplex) {
 			tp->full_duplex = duplex;
 			printk (KERN_INFO
 				"%s: Setting %s-duplex based on MII #%d link"
 				" partner ability of %4.4x.\n", dev->name,
 				tp->full_duplex ? "full" : "half",
-				tp->phys[0], mii_reg5);
+				tp->phys[0], mii_lpa);
 			NETDRV_W8 (Cfg9346, Cfg9346_Unlock);
 			NETDRV_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
 			NETDRV_W8 (Cfg9346, Cfg9346_Lock);
@@ -1980,7 +1980,7 @@
 	name:		MODNAME,
 	id_table:	netdrv_pci_tbl,
 	probe:		netdrv_init_one,
-	remove:		netdrv_remove_one,
+	remove:		__devexit_p(netdrv_remove_one),
 #ifdef CONFIG_PM
 	suspend:	netdrv_suspend,
 	resume:		netdrv_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- linux-2.4.16/drivers/net/pcmcia/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pcmcia/Config.in	Tue Dec  4 19:25:30 2001
@@ -11,10 +11,10 @@
    dep_tristate '  3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA
    dep_tristate '  Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA
    dep_tristate '  NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA
+   dep_tristate '  Asix AX88190 PCMCIA support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA
    dep_tristate '  New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA
    dep_tristate '  SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
    dep_tristate '  Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
-   dep_tristate '  broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA
    dep_tristate '  COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
    if [ "$CONFIG_IBMTR" != "y" ]; then
       dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pcmcia/ax8390.h linux/drivers/net/pcmcia/ax8390.h
--- linux-2.4.16/drivers/net/pcmcia/ax8390.h	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pcmcia/ax8390.h	Thu Jan  1 00:00:00 1970
@@ -1,193 +0,0 @@
-/* Generic NS8390 register definitions. */
-/* This file is part of Donald Becker's 8390 drivers, and is distributed
-   under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
-   Some of these names and comments originated from the Crynwr
-   packet drivers, which are distributed under the GPL. */
-
-#ifndef _8390_h
-#define _8390_h
-
-#include <linux/config.h>
-#include <linux/if_ether.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-
-#define TX_2X_PAGES 12
-#define TX_1X_PAGES 6
-
-/* Should always use two Tx slots to get back-to-back transmits. */
-#define EI_PINGPONG
-
-#ifdef EI_PINGPONG
-#define TX_PAGES TX_2X_PAGES
-#else
-#define TX_PAGES TX_1X_PAGES
-#endif
-
-#define ETHER_ADDR_LEN 6
-
-/* The 8390 specific per-packet-header format. */
-struct e8390_pkt_hdr {
-  unsigned char status; /* status */
-  unsigned char next;   /* pointer to next packet. */
-  unsigned short count; /* header + packet length in bytes */
-};
-
-#ifdef notdef
-extern int ei_debug;
-#else
-#define ei_debug 1
-#endif
-
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c */
-extern void autoirq_setup(int waittime);
-extern unsigned long autoirq_report(int waittime);
-#endif
-
-static int ethdev_init(struct net_device *dev);
-static void NS8390_init(struct net_device *dev, int startp);
-static int ei_open(struct net_device *dev);
-static int ei_close(struct net_device *dev);
-static void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-/* Most of these entries should be in 'struct net_device' (or most of the
-   things in there should be here!) */
-/* You have one of these per-board */
-struct ei_device {
-	const char *name;
-	void (*reset_8390)(struct net_device *);
-	void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
-	void (*block_output)(struct net_device *, int, const unsigned char *, int);
-	void (*block_input)(struct net_device *, int, struct sk_buff *, int);
-	unsigned char mcfilter[8];
-	unsigned open:1;
-	unsigned word16:1;  		/* We have the 16-bit (vs 8-bit) version of the card. */
-	unsigned txing:1;		/* Transmit Active */
-	unsigned irqlock:1;		/* 8390's intrs disabled when '1'. */
-	unsigned dmaing:1;		/* Remote DMA Active */
-	unsigned char tx_start_page, rx_start_page, stop_page;
-	unsigned char current_page;	/* Read pointer in buffer  */
-	unsigned char interface_num;	/* Net port (AUI, 10bT.) to use. */
-	unsigned char txqueue;		/* Tx Packet buffer queue length. */
-	short tx1, tx2;			/* Packet lengths for ping-pong tx. */
-	short lasttx;			/* Alpha version consistency check. */
-	unsigned char reg0;		/* Register '0' in a WD8013 */
-	unsigned char reg5;		/* Register '5' in a WD8013 */
-	unsigned char saved_irq;	/* Original dev->irq value. */
-	struct net_device_stats stat;	/* The new statistics table. */
-	u32 *reg_offset;		/* Register mapping table */
-	spinlock_t page_lock;		/* Page register locks */
-	unsigned long priv;		/* Private field to store bus IDs etc. */
-};
-
-/* The maximum number of 8390 interrupt service routines called per IRQ. */
-#define MAX_SERVICE 12
-
-/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
-#define TX_TIMEOUT (20*HZ/100)
-
-#define ei_status (*(struct ei_device *)(dev->priv))
-
-/* Some generic ethernet register configurations. */
-#define E8390_TX_IRQ_MASK	0xa	/* For register EN0_ISR */
-#define E8390_RX_IRQ_MASK	0x5
-#define E8390_RXCONFIG		0x44	/* EN0_RXCR: broadcasts, no multicast,errors */
-#define E8390_RXOFF		0x20	/* EN0_RXCR: Accept no packets */
-#define E8390_TXCONFIG		0x00	/* EN0_TXCR: Normal transmit mode */
-#define E8390_TXOFF		0x02	/* EN0_TXCR: Transmitter off */
-
-/*  Register accessed at EN_CMD, the 8390 base addr.  */
-#define E8390_STOP	0x01	/* Stop and reset the chip */
-#define E8390_START	0x02	/* Start the chip, clear reset */
-#define E8390_TRANS	0x04	/* Transmit a frame */
-#define E8390_RREAD	0x08	/* Remote read */
-#define E8390_RWRITE	0x10	/* Remote write  */
-#define E8390_NODMA	0x20	/* Remote DMA */
-#define E8390_PAGE0	0x00	/* Select page chip registers */
-#define E8390_PAGE1	0x40	/* using the two high-order bits */
-#define E8390_PAGE2	0x80	/* Page 3 is invalid. */
-
-/*
- *	Only generate indirect loads given a machine that needs them.
- */
- 
-#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
-    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
-    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
-#define EI_SHIFT(x)	(ei_local->reg_offset[x])
-#else
-#define EI_SHIFT(x)	(x)
-#endif
-
-#define E8390_CMD	EI_SHIFT(0x00)  /* The command register (for all pages) */
-/* Page 0 register offsets. */
-#define EN0_CLDALO	EI_SHIFT(0x01)	/* Low byte of current local dma addr  RD */
-#define EN0_STARTPG	EI_SHIFT(0x01)	/* Starting page of ring bfr WR */
-#define EN0_CLDAHI	EI_SHIFT(0x02)	/* High byte of current local dma addr  RD */
-#define EN0_STOPPG	EI_SHIFT(0x02)	/* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY	EI_SHIFT(0x03)	/* Boundary page of ring bfr RD WR */
-#define EN0_TSR		EI_SHIFT(0x04)	/* Transmit status reg RD */
-#define EN0_TPSR	EI_SHIFT(0x04)	/* Transmit starting page WR */
-#define EN0_NCR		EI_SHIFT(0x05)	/* Number of collision reg RD */
-#define EN0_TCNTLO	EI_SHIFT(0x05)	/* Low  byte of tx byte count WR */
-#define EN0_FIFO	EI_SHIFT(0x06)	/* FIFO RD */
-#define EN0_TCNTHI	EI_SHIFT(0x06)	/* High byte of tx byte count WR */
-#define EN0_ISR		EI_SHIFT(0x07)	/* Interrupt status reg RD WR */
-#define EN0_CRDALO	EI_SHIFT(0x08)	/* low byte of current remote dma address RD */
-#define EN0_RSARLO	EI_SHIFT(0x08)	/* Remote start address reg 0 */
-#define EN0_CRDAHI	EI_SHIFT(0x09)	/* high byte, current remote dma address RD */
-#define EN0_RSARHI	EI_SHIFT(0x09)	/* Remote start address reg 1 */
-#define EN0_RCNTLO	EI_SHIFT(0x0a)	/* Remote byte count reg WR */
-#define EN0_RCNTHI	EI_SHIFT(0x0b)	/* Remote byte count reg WR */
-#define EN0_RSR		EI_SHIFT(0x0c)	/* rx status reg RD */
-#define EN0_RXCR	EI_SHIFT(0x0c)	/* RX configuration reg WR */
-#define EN0_TXCR	EI_SHIFT(0x0d)	/* TX configuration reg WR */
-#define EN0_COUNTER0	EI_SHIFT(0x0d)	/* Rcv alignment error counter RD */
-#define EN0_DCFG	EI_SHIFT(0x0e)	/* Data configuration reg WR */
-#define EN0_COUNTER1	EI_SHIFT(0x0e)	/* Rcv CRC error counter RD */
-#define EN0_IMR		EI_SHIFT(0x0f)	/* Interrupt mask reg WR */
-#define EN0_COUNTER2	EI_SHIFT(0x0f)	/* Rcv missed frame error counter RD */
-
-/* Bits in EN0_ISR - Interrupt status register */
-#define ENISR_RX	0x01	/* Receiver, no error */
-#define ENISR_TX	0x02	/* Transmitter, no error */
-#define ENISR_RX_ERR	0x04	/* Receiver, with error */
-#define ENISR_TX_ERR	0x08	/* Transmitter, with error */
-#define ENISR_OVER	0x10	/* Receiver overwrote the ring */
-#define ENISR_COUNTERS	0x20	/* Counters need emptying */
-#define ENISR_RDC	0x40	/* remote dma complete */
-#define ENISR_RESET	0x80	/* Reset completed */
-#define ENISR_ALL	0x3f	/* Interrupts we will enable */
-
-/* Bits in EN0_DCFG - Data config register */
-#define ENDCFG_WTS	0x01	/* word transfer mode selection */
-
-/* Page 1 register offsets. */
-#define EN1_PHYS   EI_SHIFT(0x01)	/* This board's physical enet addr RD WR */
-#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
-#define EN1_CURPAG EI_SHIFT(0x07)	/* Current memory page RD WR */
-#define EN1_MULT   EI_SHIFT(0x08)	/* Multicast filter mask array (8 bytes) RD WR */
-#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
-
-/* Bits in received packet status byte and EN0_RSR*/
-#define ENRSR_RXOK	0x01	/* Received a good packet */
-#define ENRSR_CRC	0x02	/* CRC error */
-#define ENRSR_FAE	0x04	/* frame alignment error */
-#define ENRSR_FO	0x08	/* FIFO overrun */
-#define ENRSR_MPA	0x10	/* missed pkt */
-#define ENRSR_PHY	0x20	/* physical/multicast address */
-#define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
-#define ENRSR_DEF	0x80	/* deferring */
-
-/* Transmitted packet status, EN0_TSR. */
-#define ENTSR_PTX 0x01	/* Packet transmitted without error */
-#define ENTSR_ND  0x02	/* The transmit wasn't deferred. */
-#define ENTSR_COL 0x04	/* The transmit collided at least once. */
-#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
-#define ENTSR_CRS 0x10	/* The carrier sense was lost. */
-#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
-#define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
-#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
-
-#endif /* _8390_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pcmcia/axnet_cs.c linux/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.16/drivers/net/pcmcia/axnet_cs.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pcmcia/axnet_cs.c	Tue Dec  4 19:25:30 2001
@@ -11,7 +11,7 @@
 
     Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
 
-    axnet_cs.c 1.11 2001/06/12 12:42:40
+    axnet_cs.c 1.24 2001/11/18 02:46:51
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -20,7 +20,7 @@
     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.
-    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+    Donald Becker may be reached at becker@scyld.com
 
 ======================================================================*/
 
@@ -33,12 +33,13 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include <linux/netdevice.h>
-#include "ax8390.h"
+#include "../8390.h"
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -51,7 +52,6 @@
 #define AXNET_CMD	0x00
 #define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
 #define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define AXNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
 #define AXNET_MII_EEP	0x14	/* Offset of MII access port */
 
 #define AXNET_START_PG	0x40	/* First page of TX buffer */
@@ -59,26 +59,13 @@
 
 #define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
 
-#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 =
-"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
-#define skb_tx_check(dev, skb)
-#define add_rx_bytes(stats, n) (stats)->rx_bytes += n;
-#define add_tx_bytes(stats, n) (stats)->tx_bytes += n;
-#define netif_mark_up(dev)	do { } while (0)
-#define netif_mark_down(dev)	do { } while (0)
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
@@ -87,9 +74,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Ugh!  Let the user hardwire the hardware address for queer cards */
-static int hw_addr[6] = { 0, /* ... */ };
-MODULE_PARM(hw_addr, "6i");
+#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 =
+"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -120,6 +112,11 @@
 static dev_info_t dev_info = "axnet_cs";
 static dev_link_t *dev_list;
 
+static int axdev_init(struct net_device *dev);
+static void AX88190_init(struct net_device *dev, int startp);
+static int ax_open(struct net_device *dev);
+static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
 /*====================================================================*/
 
 typedef struct axnet_dev_t {
@@ -210,7 +207,7 @@
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    ethdev_init(dev);
+    axdev_init(dev);
     dev->init = &axnet_init;
     dev->open = &axnet_open;
     dev->stop = &axnet_close;
@@ -302,7 +299,7 @@
 	{0x00,	EN0_RCNTHI},
 	{0x00,	EN0_IMR},	/* Mask completion irq. */
 	{0xFF,	EN0_ISR},
-	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+	{E8390_RXOFF|0x40, EN0_RXCR},	/* 0x60  Set to monitor */
 	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
 	{0x10,	EN0_RCNTLO},
 	{0x00,	EN0_RCNTHI},
@@ -331,30 +328,6 @@
 
 /*======================================================================
 
-    This should be totally unnecessary... but when we can't figure
-    out the hardware address any other way, we'll let the user hard
-    wire it when the module is initialized.
-
-======================================================================*/
-
-static int get_hwired(dev_link_t *link)
-{
-    struct net_device *dev = link->priv;
-    int i;
-
-    for (i = 0; i < 6; i++)
-	if (hw_addr[i] != 0) break;
-    if (i == 6)
-	return 0;
-
-    for (i = 0; i < 6; i++)
-	dev->dev_addr[i] = hw_addr[i];
-
-    return 1;
-} /* get_hwired */
-
-/*======================================================================
-
     axnet_config() is scheduled to run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
@@ -419,7 +392,8 @@
     CS_CHECK(GetTupleData, handle, &tuple);
     CS_CHECK(ParseTuple, handle, &tuple, &parse);
     link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
+    /* don't trust the CIS on this; Linksys got it wrong */
+    link->conf.Present = 0x63;
 
     /* Configure card */
     link->state |= DEV_CONFIG;
@@ -440,7 +414,7 @@
 	if ((cfg->index == 0) || (cfg->io.nwin == 0))
 	    goto next_entry;
 	
-	link->conf.ConfigIndex = cfg->index;
+	link->conf.ConfigIndex = 0x05;
 	/* For multifunction cards, by convention, we configure the
 	   network function with window 0, and serial with window 1 */
 	if (io->nwin > 1) {
@@ -480,9 +454,9 @@
 	goto failed;
     }
 
-    if (!get_prom(link) && !get_hwired(link)) {
-	printk(KERN_NOTICE "axnet_cs: unable to read hardware net"
-	       " address for io base %#3lx\n", dev->base_addr);
+    if (!get_prom(link)) {
+	printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n");
+	printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n");
 	unregister_netdev(dev);
 	goto failed;
     }
@@ -542,7 +516,7 @@
 
     if (link->open) {
 	DEBUG(1, "axnet_cs: release postponed, '%s' still open\n",
-	      info->node.dev_name);
+	      ((axnet_dev_t *)(link->priv))->node.dev_name);
 	link->state |= DEV_STALE_CONFIG;
 	return;
     }
@@ -602,7 +576,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		axnet_reset_8390(&info->dev);
-		NS8390_init(&info->dev, 1);
+		AX88190_init(&info->dev, 1);
 		netif_device_attach(&info->dev);
 	    }
 	}
@@ -692,7 +666,7 @@
     info->watchdog.expires = jiffies + HZ;
     add_timer(&info->watchdog);
 
-    return ei_open(dev);
+    return ax_open(dev);
 } /* axnet_open */
 
 /*====================================================================*/
@@ -708,7 +682,6 @@
     
     link->open--;
     netif_stop_queue(dev);
-    netif_mark_down(dev);
     del_timer(&info->watchdog);
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
@@ -755,7 +728,7 @@
 {
     axnet_dev_t *info = dev_id;
     info->stale = 0;
-    ei_interrupt(irq, dev_id, regs);
+    ax_interrupt(irq, dev_id, regs);
 }
 
 static void ei_watchdog(u_long arg)
@@ -807,7 +780,7 @@
 	    else
 		printk(KERN_INFO "%s: link partner did not autonegotiate\n",
 		       dev->name);
-	    NS8390_init(dev, 1);
+	    AX88190_init(dev, 1);
 	}
 	info->link_status = link;
     }
@@ -944,10 +917,11 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-  
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
   This is the chip-specific code for many 8390-based ethernet adaptors.
   This is not a complete driver, it must be combined with board-specific
   code such as ne.c, wd.c, 3c503.c, etc.
@@ -957,7 +931,6 @@
   a simple innocent change. Please contact me or Donald if you think
   you have found something that needs changing. -- PG
 
-
   Changelog:
 
   Paul Gortmaker	: remove set_bit lock, other cleanups.
@@ -981,8 +954,8 @@
 
   */
 
-static const char *version =
-    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+static const char *version_8390 =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -1062,25 +1035,23 @@
  *	them.
  */
  
-
-
 /**
- * ei_open - Open/initialize the board.
+ * ax_open - Open/initialize the board.
  * @dev: network device to initialize
  *
  * This routine goes all-out, setting everything
  * up anew at each open, even though many of these registers should only
  * need to be set once at boot.
  */
-static int ei_open(struct net_device *dev)
+static int ax_open(struct net_device *dev)
 {
 	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
-	/* This can't happen unless somebody forgot to call ethdev_init(). */
+	/* This can't happen unless somebody forgot to call axdev_init(). */
 	if (ei_local == NULL) 
 	{
-		printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
+		printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name);
 		return -ENXIO;
 	}
 
@@ -1099,10 +1070,9 @@
 	 */
       
       	spin_lock_irqsave(&ei_local->page_lock, flags);
-	NS8390_init(dev, 1);
+	AX88190_init(dev, 1);
 	/* Set the flag before we drop the lock, That way the IRQ arrives
 	   after its set and we get no silly warnings */
-	netif_mark_up(dev);
 	netif_start_queue(dev);
       	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	ei_local->irqlock = 0;
@@ -1110,27 +1080,6 @@
 }
 
 /**
- * ei_close - shut down network device
- * @dev: network device to close
- *
- * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
- */
-static int ei_close(struct net_device *dev)
-{
-	unsigned long flags;
-
-	/*
-	 *	Hold the page lock during close
-	 */
-
-	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
-	NS8390_init(dev, 0);
-	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
-	netif_stop_queue(dev);
-	return 0;
-}
-
-/**
  * ei_tx_timeout - handle transmit time out condition
  * @dev: network device which has apparently fallen asleep
  *
@@ -1169,7 +1118,7 @@
 		
 	/* Try to restart the card.  Perhaps the user has fixed something. */
 	ei_reset_8390(dev);
-	NS8390_init(dev, 1);
+	AX88190_init(dev, 1);
 		
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
@@ -1192,7 +1141,6 @@
 	unsigned long flags;
 
 	netif_stop_queue(dev);
-	skb_tx_check(dev, skb);
 
 	length = skb->len;
 
@@ -1205,7 +1153,6 @@
 	outb_p(0x00, e8390_base + EN0_IMR);
 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	
-	
 	/*
 	 *	Slow phase with lock held.
 	 */
@@ -1218,8 +1165,6 @@
 
 	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
     
-#ifdef EI_PINGPONG
-
 	/*
 	 * We have two Tx slots available for use. Find the first free
 	 * slot, and then perform some sanity checks. With two Tx bufs,
@@ -1288,22 +1233,6 @@
 	else
 		netif_start_queue(dev);
 
-#else	/* EI_PINGPONG */
-
-	/*
-	 * Only one Tx buffer in use. You need two Tx bufs to come close to
-	 * back-to-back transmits. Expect a 20 -> 25% performance hit on
-	 * reasonable hardware if you only use one Tx buffer.
-	 */
-
-	ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
-	ei_local->txing = 1;
-	NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
-	dev->trans_start = jiffies;
-	netif_stop_queue(dev);
-
-#endif	/* EI_PINGPONG */
-
 	/* Turn 8390 interrupts back on. */
 	ei_local->irqlock = 0;
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -1311,14 +1240,14 @@
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
 
-	DEV_KFREE_SKB (skb);
-	add_tx_bytes(&ei_local->stat, send_length);
+	dev_kfree_skb (skb);
+	ei_local->stat.tx_bytes += send_length;
     
 	return 0;
 }
 
 /**
- * ei_interrupt - handle the interrupts from an 8390
+ * ax_interrupt - handle the interrupts from an 8390
  * @irq: interrupt number
  * @dev_id: a pointer to the net_device
  * @regs: unused
@@ -1330,7 +1259,7 @@
  * needed.
  */
 
-static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void ax_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
 	long e8390_base;
@@ -1497,8 +1426,6 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int status = inb(e8390_base + EN0_TSR);
     
-#ifdef EI_PINGPONG
-
 	/*
 	 * There are two Tx buffers, see which one finished, and trigger
 	 * the send of another one if it exists.
@@ -1541,13 +1468,6 @@
 //	else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
 //			dev->name, ei_local->lasttx);
 
-#else	/* EI_PINGPONG */
-	/*
-	 *  Single Tx buffer: mark it free so another packet can be loaded.
-	 */
-	ei_local->txing = 0;
-#endif
-
 	/* Minimize Tx latency: update the statistics after we restart TXing. */
 	if (status & ENTSR_COL)
 		ei_local->stat.collisions++;
@@ -1655,7 +1575,7 @@
 				netif_rx(skb);
 				dev->last_rx = jiffies;
 				ei_local->stat.rx_packets++;
-				add_rx_bytes(&ei_local->stat, pkt_len);
+				ei_local->stat.rx_bytes += pkt_len;
 				if (pkt_stat & ENRSR_PHY)
 					ei_local->stat.multicast++;
 			}
@@ -1801,11 +1721,11 @@
 	long e8390_base = dev->base_addr;
 
   	if(dev->flags&IFF_PROMISC)
-  		outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
 	else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
-  		outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
   	else
-  		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
 }
 
 /*
@@ -1813,28 +1733,30 @@
  *	be parallel to just about everything else. Its also fairly quick and
  *	not called too often. Must protect against both bh and irq users
  */
- 
+
+#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
+
 static void set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
+	spin_lock_irqsave(&dev_lock(dev), flags);
 	do_set_multicast_list(dev);
-	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
+	spin_unlock_irqrestore(&dev_lock(dev), flags);
 }	
 
 /**
- * ethdev_init - init rest of 8390 device struct
+ * axdev_init - init rest of 8390 device struct
  * @dev: network device structure to init
  *
  * Initialize the rest of the 8390 device structure.  Do NOT __init
  * this, as it is used by 8390 based modular drivers too.
  */
 
-static int ethdev_init(struct net_device *dev)
+static int axdev_init(struct net_device *dev)
 {
 	if (ei_debug > 1)
-		printk(version);
+		printk(version_8390);
     
 	if (dev->priv == NULL) 
 	{
@@ -1857,20 +1779,18 @@
 	return 0;
 }
 
-
-
 /* This page of functions should be 8390 generic */
 /* Follow National Semi's recommendations for initializing the "NIC". */
 
 /**
- * NS8390_init - initialize 8390 hardware
+ * AX88190_init - initialize 8390 hardware
  * @dev: network device to initialize
  * @startp: boolean.  non-zero value to initiate chip processing
  *
  *	Must be called with lock held.
  */
 
-static void NS8390_init(struct net_device *dev, int startp)
+static void AX88190_init(struct net_device *dev, int startp)
 {
 	axnet_dev_t *info = (axnet_dev_t *)dev;
 	long e8390_base = dev->base_addr;
@@ -1887,7 +1807,7 @@
 	outb_p(0x00,  e8390_base + EN0_RCNTLO);
 	outb_p(0x00,  e8390_base + EN0_RCNTHI);
 	/* Set to monitor and loopback mode -- this is vital!. */
-	outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+	outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */
 	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
 	/* Set the transmit page and receive ring. */
 	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
@@ -1931,7 +1851,7 @@
 		outb_p(E8390_TXCONFIG | info->duplex_flag,
 		       e8390_base + EN0_TXCR); /* xmit on. */
 		/* 3c503 TechMan says rxconfig only after the NIC is started. */
-		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
+		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */
 		do_set_multicast_list(dev);	/* (re)load the mcast table */
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- linux-2.4.16/drivers/net/pcmcia/netwave_cs.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pcmcia/netwave_cs.c	Tue Dec  4 19:25:30 2001
@@ -200,6 +200,8 @@
 MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
 
+MODULE_LICENSE("GPL");
+
 /*====================================================================*/
 
 /* PCMCIA (Card Services) related functions */
@@ -1597,4 +1599,3 @@
     writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1);
     writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
 }
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pcmcia/xircom_cb.c linux/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.16/drivers/net/pcmcia/xircom_cb.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pcmcia/xircom_cb.c	Fri Dec  7 18:08:43 2001
@@ -170,7 +170,7 @@
 	name:		"xircom_cb", 
 	id_table:	xircom_pci_table, 
 	probe:		xircom_probe, 
-	remove:		xircom_remove, 
+	remove:		__devexit_p(xircom_remove), 
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.4.16/drivers/net/pcmcia/xircom_tulip_cb.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Fri Dec  7 18:08:43 2001
@@ -1748,7 +1748,7 @@
 	name:		DRV_NAME,
 	id_table:	xircom_pci_table,
 	probe:		xircom_init_one,
-	remove:		xircom_remove_one,
+	remove:		__devexit_p(xircom_remove_one),
 #ifdef CONFIG_PM
 	suspend:	xircom_suspend,
 	resume:		xircom_resume
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/shaper.c linux/drivers/net/shaper.c
--- linux-2.4.16/drivers/net/shaper.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/shaper.c	Tue Dec  4 19:25:30 2001
@@ -737,6 +737,11 @@
 
 static void __exit shaper_exit (void)
 {
+	int i;
+
+	for (i = 0; i < shapers; i++)
+		unregister_netdev(&devs[i]);
+
 	kfree(devs);
 	devs = NULL;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/sis900.c linux/drivers/net/sis900.c
--- linux-2.4.16/drivers/net/sis900.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/sis900.c	Fri Dec  7 18:08:43 2001
@@ -2098,7 +2098,7 @@
 	name:		SIS900_MODULE_NAME,
 	id_table:	sis900_pci_tbl,
 	probe:		sis900_probe,
-	remove:		sis900_remove,
+	remove:		__devexit_p(sis900_remove),
 };
 
 static int __init sis900_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/starfire.c linux/drivers/net/starfire.c
--- linux-2.4.16/drivers/net/starfire.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/starfire.c	Fri Dec  7 18:08:43 2001
@@ -1963,7 +1963,7 @@
 static struct pci_driver starfire_driver = {
 	name:		DRV_NAME,
 	probe:		starfire_init_one,
-	remove:		starfire_remove_one,
+	remove:		__devexit_p(starfire_remove_one),
 	id_table:	starfire_pci_tbl,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/sundance.c linux/drivers/net/sundance.c
--- linux-2.4.16/drivers/net/sundance.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/sundance.c	Fri Dec  7 18:08:43 2001
@@ -1474,7 +1474,7 @@
 	name:		DRV_NAME,
 	id_table:	sundance_pci_tbl,
 	probe:		sundance_probe1,
-	remove:		sundance_remove1,
+	remove:		__devexit_p(sundance_remove1),
 };
 
 static int __init sundance_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/sungem.c linux/drivers/net/sungem.c
--- linux-2.4.16/drivers/net/sungem.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/sungem.c	Fri Dec  7 18:08:43 2001
@@ -1,7 +1,15 @@
-/* $Id: sungem.c,v 1.30 2001/10/17 06:55:10 davem Exp $
+/* $Id: sungem.c,v 1.43 2001/12/05 08:40:54 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ * 
+ * Support for Apple GMAC and assorted PHYs by
+ * Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * 
+ * TODO: 
+ *  - Get rid of all those nasty mdelay's and replace them
+ * with schedule_timeout.
+ *  - Implement WOL
  */
 
 #include <linux/module.h>
@@ -23,11 +31,15 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
 
 #ifdef __sparc__
 #include <asm/idprom.h>
@@ -45,15 +57,33 @@
 
 #include "sungem.h"
 
+#define DRV_NAME	"sungem"
+#define DRV_VERSION	"0.96"
+#define DRV_RELDATE	"11/17/01"
+#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
+
 static char version[] __devinitdata =
-        "sungem.c:v0.95 16/Oct/01 David S. Miller (davem@redhat.com)\n";
+        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
 
-MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_AUTHOR(DRV_AUTHOR);
 MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(gem_debug, "i");
 MODULE_PARM_DESC(gem_debug, "(ignored)");
+MODULE_PARM(link_mode, "i");
+
+static int link_mode;
+
+static u16 link_modes[] __devinitdata = {
+	BMCR_ANENABLE,			/* 0 : autoneg */
+	0,				/* 1 : 10bt half duplex */
+	BMCR_SPEED100,			/* 2 : 100bt half duplex */
+	BMCR_SPD2, /* verify this */	/* 3 : 1000bt half duplex */
+	BMCR_FULLDPLX,			/* 4 : 10bt full duplex */
+	BMCR_SPEED100|BMCR_FULLDPLX,	/* 5 : 100bt full duplex */
+	BMCR_SPD2|BMCR_FULLDPLX		/* 6 : 1000bt full duplex */
+};
 
 #define GEM_MODULE_NAME	"gem"
 #define PFX GEM_MODULE_NAME ": "
@@ -73,7 +103,7 @@
 	 * they only support 10/100 speeds. -DaveM
 	 * 
 	 * Apple's GMAC does support gigabit on machines with
-	 * the BCM5400 or 5401 PHYs. -BenH
+	 * the BCM54xx PHYs. -BenH
 	 */
 	{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -362,10 +392,6 @@
 	return 1;
 }
 
-static void gem_stop(struct gem *, unsigned long);
-static void gem_init_rings(struct gem *, int);
-static void gem_init_hw(struct gem *);
-
 /* All non-normal interrupt conditions get serviced here.
  * Returns non-zero if we should just exit the interrupt
  * handler right now (ie. if we reset the card which invalidates
@@ -418,9 +444,9 @@
 	return 0;
 
 do_reset:
-	gem_stop(gp, gp->regs);
-	gem_init_rings(gp, 1);
-	gem_init_hw(gp);
+	gp->reset_task_pending = 1;
+	schedule_task(&gp->reset_task);
+
 	return 1;
 }
 
@@ -627,6 +653,10 @@
 	struct gem *gp = dev->priv;
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+	if (!gp->hw_running) {
+		printk("%s: hrm.. hw not running !\n", dev->name);
+		return;
+	}
 	printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n",
 	       dev->name,
 	       readl(gp->regs + TXDMA_CFG),
@@ -640,13 +670,19 @@
 
 	spin_lock_irq(&gp->lock);
 
-	gem_stop(gp, gp->regs);
-	gem_init_rings(gp, 1);
-	gem_init_hw(gp);
+	gp->reset_task_pending = 1;
+	schedule_task(&gp->reset_task);
 
 	spin_unlock_irq(&gp->lock);
+}
 
-	netif_wake_queue(dev);
+static __inline__ int gem_intme(int entry)
+{
+	/* Algorithm: IRQ every 1/2 of descriptors. */
+	if (!(entry & ((TX_RING_SIZE>>1)-1)))
+		return 1;
+
+	return 0;
 }
 
 static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -690,15 +726,22 @@
 					~PAGE_MASK),
 				       len, PCI_DMA_TODEVICE);
 		ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len;
+		if (gem_intme(entry))
+			ctrl |= TXDCTRL_INTME;
 		txd->buffer = cpu_to_le64(mapping);
 		txd->control_word = cpu_to_le64(ctrl);
 		entry = NEXT_TX(entry);
 	} else {
 		struct gem_txd *txd;
 		u32 first_len;
+		u64 intme;
 		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
 
+		intme = 0;
+		if (gem_intme(entry))
+			intme |= TXDCTRL_INTME;
+
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
@@ -727,11 +770,15 @@
 			txd->buffer = cpu_to_le64(mapping);
 			txd->control_word = cpu_to_le64(this_ctrl | len);
 
+			if (gem_intme(entry))
+				intme |= TXDCTRL_INTME;
+
 			entry = NEXT_TX(entry);
 		}
 		txd = &gp->init_block->txd[first_entry];
 		txd->buffer = cpu_to_le64(first_mapping);
-		txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | first_len);
+		txd->control_word =
+			cpu_to_le64(ctrl | TXDCTRL_SOF | intme | first_len);
 	}
 
 	gp->tx_new = entry;
@@ -761,18 +808,19 @@
 		return -EINVAL;
 
 	spin_lock_irq(&gp->lock);
-	gem_stop(gp, gp->regs);
 	dev->mtu = new_mtu;
-	gem_init_rings(gp, 1);
-	gem_init_hw(gp);
+	gp->reset_task_pending = 1;
+	schedule_task(&gp->reset_task);
 	spin_unlock_irq(&gp->lock);
 
+	flush_scheduled_tasks();
+
 	return 0;
 }
 
 #define STOP_TRIES 32
 
-static void gem_stop(struct gem *gp, unsigned long regs)
+static void gem_stop(struct gem *gp)
 {
 	int limit;
 	u32 val;
@@ -781,13 +829,13 @@
 	writel(0xffffffff, gp->regs + GREG_IMASK);
 
 	/* Reset the chip */
-	writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST);
+	writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST);
 
 	limit = STOP_TRIES;
 
 	do {
 		udelay(20);
-		val = readl(regs + GREG_SWRST);
+		val = readl(gp->regs + GREG_SWRST);
 		if (limit-- <= 0)
 			break;
 	} while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
@@ -810,6 +858,9 @@
 	val = readl(gp->regs + MAC_RXCFG);
 	writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
 
+	(void) readl(gp->regs + MAC_RXCFG);
+	udelay(100);
+
 	writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
 
 	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
@@ -828,6 +879,88 @@
 	{ 1, 0, 1 },	/* 1000BT */
 };
 
+static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
+{
+	u16 ctl;
+	
+	/* Setup link parameters */
+	if (!ep)
+		goto start_aneg;
+	if (ep->autoneg == AUTONEG_ENABLE) {
+		/* TODO: parse ep->advertising */
+		gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
+		gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+		gp->link_cntl = BMCR_ANENABLE;
+	} else {
+		gp->link_cntl = 0;
+		if (ep->speed == SPEED_100)
+			gp->link_cntl |= BMCR_SPEED100;
+		else if (ep->speed == SPEED_1000 && gp->gigabit_capable)
+			/* Hrm... check if this is right... */
+			gp->link_cntl |= BMCR_SPD2;
+		if (ep->duplex == DUPLEX_FULL)
+			gp->link_cntl |= BMCR_FULLDPLX;
+	}
+
+start_aneg:
+	spin_lock_irq(&gp->lock);
+	if (!gp->hw_running) {
+		spin_unlock_irq(&gp->lock);
+		return;
+	}
+
+	/* Configure PHY & start aneg */
+	ctl = phy_read(gp, MII_BMCR);
+	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+	ctl |= gp->link_cntl;
+	if (ctl & BMCR_ANENABLE) {
+		ctl |= BMCR_ANRESTART;
+		gp->lstate = link_aneg;
+	} else {
+		gp->lstate = link_force_ok;
+	}
+	phy_write(gp, MII_BMCR, ctl);
+
+	gp->timer_ticks = 0;
+	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
+	add_timer(&gp->link_timer);
+	spin_unlock_irq(&gp->lock);
+}
+
+static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
+{
+	u32 val;
+
+	*fd = 0;
+	*spd = 10;
+	*pause = 0;
+	
+	if (gp->phy_mod == phymod_bcm5400 ||
+	    gp->phy_mod == phymod_bcm5401 ||
+	    gp->phy_mod == phymod_bcm5411) {
+		int link_mode;	
+
+	    	val = phy_read(gp, MII_BCM5400_AUXSTATUS);
+		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
+		*fd = phy_BCM5400_link_table[link_mode][0];
+		*spd = phy_BCM5400_link_table[link_mode][2] ?
+			1000 :
+			(phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
+		val = phy_read(gp, MII_LPA);
+		if (val & LPA_PAUSE)
+			*pause = 1;
+	} else {
+		val = phy_read(gp, MII_LPA);
+
+		if (val & (LPA_10FULL | LPA_100FULL))
+			*fd = 1;
+		if (val & (LPA_100FULL | LPA_100HALF))
+			*spd = 100;
+	}
+}
+
 /* A link-up condition has occurred, initialize and enable the
  * rest of the chip.
  */
@@ -842,32 +975,13 @@
 
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
-		if (gp->lstate == aneg_wait) {
-			if (gp->phy_mod == phymod_bcm5400 ||
-			    gp->phy_mod == phymod_bcm5401 ||
-			    gp->phy_mod == phymod_bcm5411) {
-				int link_mode;	
-		    		val = phy_read(gp, PHY_BCM5400_AUXSTATUS);
-		    		link_mode = (val & PHY_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
-		    			PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
-		    		full_duplex = phy_BCM5400_link_table[link_mode][0];
-		    		speed = phy_BCM5400_link_table[link_mode][2] ? 1000
-		    			: (phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
-					val = phy_read(gp, PHY_LPA);
-					if (val & PHY_LPA_PAUSE)
-						pause = 1;	
-			} else {
-				val = phy_read(gp, PHY_LPA);
-				if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
-					full_duplex = 1;
-				if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
-					speed = 100;
-			}
-		} else {
-			val = phy_read(gp, PHY_CTRL);
-			if (val & PHY_CTRL_FDPLX)
+		val = phy_read(gp, MII_BMCR);
+		if (val & BMCR_ANENABLE)
+			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
+		else {
+			if (val & BMCR_FULLDPLX)
 				full_duplex = 1;
-			if (val & PHY_CTRL_SPD100)
+			if (val & BMCR_SPEED100)
 				speed = 100;
 		}
 	} else {
@@ -944,56 +1058,142 @@
 
 static int gem_mdio_link_not_up(struct gem *gp)
 {
-	if (gp->lstate == aneg_wait) {
-		u16 val = phy_read(gp, PHY_CTRL);
+	if (gp->lstate == link_force_ret) {
+		printk(KERN_INFO "%s: Autoneg failed again, keeping"
+			" forced mode\n", gp->dev->name);
+		phy_write(gp, MII_BMCR, gp->link_fcntl);
+		gp->timer_ticks = 5;
+		gp->lstate = link_force_ok;
+	} else if (gp->lstate == link_aneg) {
+		u16 val = phy_read(gp, MII_BMCR);
 
 		/* Try forced modes. */
-		val &= ~(PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
-		val &= ~(PHY_CTRL_FDPLX);
-		val |= PHY_CTRL_SPD100;
-		phy_write(gp, PHY_CTRL, val);
-		gp->timer_ticks = 0;
-		gp->lstate = force_wait;
-		return 1;
+		val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+		val &= ~(BMCR_FULLDPLX);
+		val |= BMCR_SPEED100;
+		phy_write(gp, MII_BMCR, val);
+		gp->timer_ticks = 5;
+		gp->lstate = link_force_try;
 	} else {
 		/* Downgrade from 100 to 10 Mbps if necessary.
 		 * If already at 10Mbps, warn user about the
 		 * situation every 10 ticks.
 		 */
-		u16 val = phy_read(gp, PHY_CTRL);
-		if (val & PHY_CTRL_SPD100) {
-			val &= ~PHY_CTRL_SPD100;
-			phy_write(gp, PHY_CTRL, val);
-			gp->timer_ticks = 0;
-			return 1;
+		u16 val = phy_read(gp, MII_BMCR);
+		if (val & BMCR_SPEED100) {
+			val &= ~BMCR_SPEED100;
+			phy_write(gp, MII_BMCR, val);
+			gp->timer_ticks = 5;
 		} else {
-			printk(KERN_ERR "%s: Link down, cable problem?\n",
-			       gp->dev->name);
-			val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
-			phy_write(gp, PHY_CTRL, val);
-			gp->timer_ticks = 1;
-			gp->lstate = aneg_wait;
 			return 1;
 		}
 	}
+	return 0;
+}
+
+static void gem_init_rings(struct gem *, int);
+static void gem_init_hw(struct gem *, int);
+
+static void gem_reset_task(void *data)
+{
+	struct gem *gp = (struct gem *) data;
+
+	/* The link went down, we reset the ring, but keep
+	 * DMA stopped. Todo: Use this function for reset
+	 * on error as well.
+	 */
+	if (gp->hw_running && gp->opened) {
+		/* Make sure we don't get interrupts or tx packets */
+		spin_lock_irq(&gp->lock);
+
+		netif_stop_queue(gp->dev);
+
+		writel(0xffffffff, gp->regs + GREG_IMASK);
+
+		spin_unlock_irq(&gp->lock);
+
+		/* Reset the chip & rings */
+		gem_stop(gp);
+		gem_init_rings(gp, 0);
+		gem_init_hw(gp, 0);
+
+		netif_wake_queue(gp->dev);
+	}
+	gp->reset_task_pending = 0;
 }
 
 static void gem_link_timer(unsigned long data)
 {
 	struct gem *gp = (struct gem *) data;
-	int restart_timer = 0;
 
-	gp->timer_ticks++;
+	if (!gp->hw_running)
+		return;
+
+	/* If the link of task is still pending, we just
+	 * reschedule the link timer
+	 */
+	if (gp->reset_task_pending)
+		goto restart;
+	    	
+	spin_lock_irq(&gp->lock);
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
-		u16 val = phy_read(gp, PHY_STAT);
+		u16 val = phy_read(gp, MII_BMSR);
+		int up;
 
-		if (val & PHY_STAT_LSTAT) {
-			gem_set_link_modes(gp);
-		} else if (gp->timer_ticks < 10) {
-			restart_timer = 1;
+		/* When using autoneg, we really wait for ANEGCOMPLETE or we may
+		 * get a "transcient" incorrect link state
+		 */
+#if 0
+		{
+			u16 cntl = phy_read(gp, MII_BMCR);
+			if (cntl & BMCR_ANENABLE)
+				up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
+			else
+				up = (val & BMSR_LSTATUS) != 0;
+		}
+#else
+		up = (val & BMSR_LSTATUS) != 0;
+#endif
+		if (up) {
+			/* Ok, here we got a link. If we had it due to a forced
+			 * fallback, and we were configured for autoneg, we do
+			 * retry a short autoneg pass. If you know your hub is
+			 * broken, use ethtool ;)
+			 */
+			if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) {
+				gp->lstate = link_force_ret;
+				gp->link_fcntl = phy_read(gp, MII_BMCR);
+				gp->timer_ticks = 5;
+				printk(KERN_INFO "%s: Got link after fallback, retrying autoneg"
+				       " once...\n", gp->dev->name);
+				phy_write(gp, MII_BMCR,
+					  gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART);
+			} else if (gp->lstate != link_up) {
+				gp->lstate = link_up;
+				if (gp->opened)
+					gem_set_link_modes(gp);
+			}
 		} else {
-			restart_timer = gem_mdio_link_not_up(gp);
+			int restart = 0;
+
+			/* If the link was previously up, we restart the
+			 * whole process
+			 */
+			if (gp->lstate == link_up) {
+				gp->lstate = link_down;
+				printk(KERN_INFO "%s: Link down\n", gp->dev->name);
+				gp->reset_task_pending = 1;
+				schedule_task(&gp->reset_task);
+				restart = 1;
+			} else if (++gp->timer_ticks > 10)
+				restart = gem_mdio_link_not_up(gp);
+
+			if (restart) {
+				spin_unlock_irq(&gp->lock);
+				gem_begin_auto_negotiation(gp, NULL);
+				return;
+			}
 		}
 	} else {
 		u32 val = readl(gp->regs + PCS_MIISTAT);
@@ -1001,17 +1201,17 @@
 		if (!(val & PCS_MIISTAT_LS))
 			val = readl(gp->regs + PCS_MIISTAT);
 
-		if ((val & PCS_MIISTAT_LS) == 0) {
-			restart_timer = 1;
-		} else {
-			gem_set_link_modes(gp);
+		if ((val & PCS_MIISTAT_LS) != 0) {
+			gp->lstate = link_up;
+			if (gp->opened)
+				gem_set_link_modes(gp);
 		}
 	}
 
-	if (restart_timer) {
-		gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
-		add_timer(&gp->link_timer);
-	}
+restart:
+	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
+	add_timer(&gp->link_timer);
+	spin_unlock_irq(&gp->lock);
 }
 
 static void gem_clean_rings(struct gem *gp)
@@ -1108,66 +1308,72 @@
 	}
 }
 
-static int
-gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
+static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
 {
 	u16 val;
 	int limit = 10000;
 	
-	val = __phy_read(gp, PHY_CTRL, phy_addr);
-	val &= ~PHY_CTRL_ISO;
-	val |= PHY_CTRL_RST;
-	__phy_write(gp, PHY_CTRL, val, phy_addr);
+	val = __phy_read(gp, MII_BMCR, phy_addr);
+	val &= ~BMCR_ISOLATE;
+	val |= BMCR_RESET;
+	__phy_write(gp, MII_BMCR, val, phy_addr);
 
 	udelay(100);
 
 	while (limit--) {
-		val = __phy_read(gp, PHY_CTRL, phy_addr);
-		if ((val & PHY_CTRL_RST) == 0)
+		val = __phy_read(gp, MII_BMCR, phy_addr);
+		if ((val & BMCR_RESET) == 0)
 			break;
 		udelay(10);
 	}
-	if ((val & PHY_CTRL_ISO) && limit > 0)
-		__phy_write(gp, PHY_CTRL, val & ~PHY_CTRL_ISO, phy_addr);
+	if ((val & BMCR_ISOLATE) && limit > 0)
+		__phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr);
 	
 	return (limit <= 0);
 }
 
-static void
-gem_init_bcm5400_phy(struct gem *gp)
+static void gem_init_bcm5201_phy(struct gem *gp)
+{
+	u16 data;
+
+	data = phy_read(gp, MII_BCM5201_MULTIPHY);
+	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
+	phy_write(gp, MII_BCM5201_MULTIPHY, data);
+}
+
+static void gem_init_bcm5400_phy(struct gem *gp)
 {
 	u16 data;
 
 	/* Configure for gigabit full duplex */
-	data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
-	data |= PHY_BCM5400_AUXCONTROL_PWR10BASET;
-	phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
-	
-	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
-	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	data = phy_read(gp, MII_BCM5400_AUXCONTROL);
+	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
+	
+	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 	
 	mdelay(10);
 
 	/* Reset and configure cascaded 10/100 PHY */
 	gem_reset_one_mii_phy(gp, 0x1f);
 	
-	data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
-	data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
-	__phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+	data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
 
-	data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
-	data &= ~PHY_BCM5400_AUXCONTROL_PWR10BASET;
-	phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+	data = phy_read(gp, MII_BCM5400_AUXCONTROL);
+	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
 }
 
-static void
-gem_init_bcm5401_phy(struct gem *gp)
+static void gem_init_bcm5401_phy(struct gem *gp)
 {
 	u16 data;
 	int rev;
 
-	rev = phy_read(gp, PHY_ID1) & 0x000f;
+	rev = phy_read(gp, MII_PHYSID2) & 0x000f;
 	if (rev == 0 || rev == 3) {
 		/* Some revisions of 5401 appear to need this
 		 * initialisation sequence to disable, according
@@ -1191,22 +1397,21 @@
 	}
 	
 	/* Configure for gigabit full duplex */
-	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
-	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 
 	mdelay(1);
 
 	/* Reset and configure cascaded 10/100 PHY */
 	gem_reset_one_mii_phy(gp, 0x1f);
 	
-	data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
-	data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
-	__phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+	data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
 }
 
-static void
-gem_init_bcm5411_phy(struct gem *gp)
+static void gem_init_bcm5411_phy(struct gem *gp)
 {
 	u16 data;
 
@@ -1220,20 +1425,30 @@
 	/* Here, Apple seems to want to reset it, do
 	 * it as well
 	 */
-	phy_write(gp, PHY_CTRL, PHY_CTRL_RST);
+	phy_write(gp, MII_BMCR, BMCR_RESET);
 
 	/* Start autoneg */
-	phy_write(gp, PHY_CTRL,
-		  (PHY_CTRL_ANENAB | PHY_CTRL_FDPLX |
-		   PHY_CTRL_ANRES | PHY_CTRL_SPD2));
-
-	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
-	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	phy_write(gp, MII_BMCR,
+		  (BMCR_ANENABLE | BMCR_FULLDPLX |
+		   BMCR_ANRESTART | BMCR_SPD2));
+
+	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 }
 
 static void gem_init_phy(struct gem *gp)
 {
+	u32 mifcfg;
+
+	if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
+		phy_write(gp, MII_BCM5201_INTERRUPT, 0);
+
+	/* Revert MIF CFG setting done on stop_phy */
+	mifcfg = readl(gp->regs + MIF_CFG);
+	mifcfg &= ~MIF_CFG_BBMODE;
+	writel(mifcfg, gp->regs + MIF_CFG);
+	
 #ifdef CONFIG_ALL_PPC
 	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		int i;
@@ -1241,7 +1456,7 @@
 		pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
 		for (i = 0; i < 32; i++) {
 			gp->mii_phy_addr = i;
-			if (phy_read(gp, PHY_CTRL) != 0xffff)
+			if (phy_read(gp, MII_BMCR) != 0xffff)
 				break;
 		}
 		if (i == 32) {
@@ -1277,54 +1492,68 @@
 		/* Take PHY out of isloate mode and reset it. */
 		gem_reset_one_mii_phy(gp, gp->mii_phy_addr);
 
-		phy_id = (phy_read(gp, PHY_ID0) << 16 | phy_read(gp, PHY_ID1))
+		phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2))
 			 	& 0xfffffff0;
 		printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id);
 		switch(phy_id) {
-			case 0x406210:
-				gp->phy_mod = phymod_bcm5201;
-				printk("BCM 5201\n");
-				break;
-			case 0x4061e0:
-				printk("BCM 5221\n");
-				gp->phy_mod = phymod_bcm5221;
-				break;
-			case 0x206040:
-				printk("BCM 5400\n");
-				gp->phy_mod = phymod_bcm5400;
-				gem_init_bcm5400_phy(gp);
-				break;
-			case 0x206050:
-				printk("BCM 5401\n");
-				gp->phy_mod = phymod_bcm5401;
-				gem_init_bcm5401_phy(gp);
-				break;
-			case 0x206070:
-				printk("BCM 5411\n");
-				gp->phy_mod = phymod_bcm5411;
-				gem_init_bcm5411_phy(gp);
-				break;
-			default:
-				printk("Generic\n");
-				gp->phy_mod = phymod_generic;
+		case 0x406210:
+			gp->phy_mod = phymod_bcm5201;
+			gem_init_bcm5201_phy(gp);
+			printk("BCM 5201\n");
+			break;
+
+		case 0x4061e0:
+			printk("BCM 5221\n");
+			gp->phy_mod = phymod_bcm5221;
+			break;
+
+		case 0x206040:
+			printk("BCM 5400\n");
+			gp->phy_mod = phymod_bcm5400;
+			gem_init_bcm5400_phy(gp);
+			gp->gigabit_capable = 1;
+			break;
+
+		case 0x206050:
+			printk("BCM 5401\n");
+			gp->phy_mod = phymod_bcm5401;
+			gem_init_bcm5401_phy(gp);
+			gp->gigabit_capable = 1;
+			break;
+
+		case 0x206070:
+			printk("BCM 5411\n");
+			gp->phy_mod = phymod_bcm5411;
+			gem_init_bcm5411_phy(gp);
+			gp->gigabit_capable = 1;
+			break;
+
+		case 0x18074c0:
+			printk("Lucent\n");
+			gp->phy_mod = phymod_generic;
+			break;
+
+		case 0x437420:
+			printk("Enable Semiconductor\n");
+			gp->phy_mod = phymod_generic;
+			break;
+
+		default:
+			printk("Unknown\n");
+			gp->phy_mod = phymod_generic;
+			break;
 		};
 
 		/* Init advertisement and enable autonegotiation. */
-		val = phy_read(gp, PHY_CTRL);
-		val &= ~PHY_CTRL_ANENAB;
-		phy_write(gp, PHY_CTRL, val);
+		val = phy_read(gp, MII_BMCR);
+		val &= ~BMCR_ANENABLE;
+		phy_write(gp, MII_BMCR, val);
 		udelay(10);
 		
-		phy_write(gp, PHY_ADV,
-			  phy_read(gp, PHY_ADV) |
-			  (PHY_ADV_10HALF | PHY_ADV_10FULL |
-			   PHY_ADV_100HALF | PHY_ADV_100FULL));
-
-		val = phy_read(gp, PHY_CTRL);
-		val |= PHY_CTRL_ANENAB;
-		phy_write(gp, PHY_CTRL, val);
-		val |= PHY_CTRL_ANRES;
-		phy_write(gp, PHY_CTRL, val);
+		phy_write(gp, MII_ADVERTISE,
+			  phy_read(gp, MII_ADVERTISE) |
+			  (ADVERTISE_10HALF | ADVERTISE_10FULL |
+			   ADVERTISE_100HALF | ADVERTISE_100FULL));
 	} else {
 		u32 val;
 		int limit;
@@ -1379,6 +1608,7 @@
 		else
 			val |= PCS_SCTRL_LOOP;
 		writel(val, gp->regs + PCS_SCTRL);
+		gp->gigabit_capable = 1;
 	}
 }
 
@@ -1392,7 +1622,7 @@
 
 	writel(desc_dma >> 32, gp->regs + TXDMA_DBHI);
 	writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW);
-	desc_dma += (TX_RING_SIZE * sizeof(struct gem_txd));
+	desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
 
 	writel(0, gp->regs + TXDMA_KICK);
 
@@ -1410,12 +1640,12 @@
 	writel(val, gp->regs + RXDMA_PTHRESH);
 
 	if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
-		writel(((6 & RXDMA_BLANK_IPKTS) |
-			((4 << 12) & RXDMA_BLANK_ITIME)),
+		writel(((5 & RXDMA_BLANK_IPKTS) |
+			((8 << 12) & RXDMA_BLANK_ITIME)),
 		       gp->regs + RXDMA_BLANK);
 	else
-		writel(((6 & RXDMA_BLANK_IPKTS) |
-			((2 << 12) & RXDMA_BLANK_ITIME)),
+		writel(((5 & RXDMA_BLANK_IPKTS) |
+			((4 << 12) & RXDMA_BLANK_ITIME)),
 		       gp->regs + RXDMA_BLANK);
 }
 
@@ -1551,18 +1781,20 @@
 	writel(0, gp->regs + MAC_MCCFG);
 	writel(0, gp->regs + MAC_XIFCFG);
 
-	writel((MAC_TXSTAT_URUN | MAC_TXSTAT_MPE |
-		MAC_TXSTAT_NCE | MAC_TXSTAT_ECE |
-		MAC_TXSTAT_LCE | MAC_TXSTAT_FCE |
-		MAC_TXSTAT_DTE | MAC_TXSTAT_PCE), gp->regs + MAC_TXMASK);
-	writel((MAC_RXSTAT_OFLW | MAC_RXSTAT_FCE |
-		MAC_RXSTAT_ACE | MAC_RXSTAT_CCE |
-		MAC_RXSTAT_LCE | MAC_RXSTAT_VCE), gp->regs + MAC_RXMASK);
-	writel(0, gp->regs + MAC_MCMASK);
+	/* Setup MAC interrupts.  We want to get all of the interesting
+	 * counter expiration events, but we do not want to hear about
+	 * normal rx/tx as the DMA engine tells us that.
+	 */
+	writel(MAC_TXSTAT_XMIT, gp->regs + MAC_TXMASK);
+	writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
+
+	/* Don't enable even the PAUSE interrupts for now, we
+	 * make no use of those events other than to record them.
+	 */
+	writel(0xffffffff, gp->regs + MAC_MCMASK);
 }
 
-static void
-gem_init_pause_thresholds(struct gem* gp)
+static void gem_init_pause_thresholds(struct gem *gp)
 {
 	/* Calculate pause thresholds.  Setting the OFF threshold to the
 	 * full RX fifo size effectively disables PAUSE generation which
@@ -1580,11 +1812,7 @@
 	}
 
 	{
-		u32 cfg = readl(gp->regs + GREG_BIFCFG);
-
-		/* XXX Why do I do this? -DaveM XXX */
-		cfg |= GREG_BIFCFG_B64DIS;
-		writel(cfg, gp->regs + GREG_BIFCFG);
+		u32 cfg;
 
 		cfg  = GREG_CFG_IBURST;
 		cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
@@ -1598,21 +1826,15 @@
 	struct pci_dev *pdev = gp->pdev;
 	u32 mif_cfg;
 
-	/* On Apple's sungem, we can't realy on registers as the chip
+	/* On Apple's sungem, we can't rely on registers as the chip
 	 * was been powered down by the firmware. We do the PHY lookup
 	 * when the interface is opened and we configure the driver
 	 * with known values.
 	 */
 	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gp->phy_type = phy_mii_mdio0;
-		mif_cfg = readl(gp->regs + MIF_CFG);
-		mif_cfg &= ~MIF_CFG_PSELECT;
-		writel(mif_cfg, gp->regs + MIF_CFG);
-		writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
-		writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
 		gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
 		gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
-		gem_init_pause_thresholds(gp);
 		return 0;
 	}
 
@@ -1651,7 +1873,7 @@
 
 		for (i = 0; i < 32; i++) {
 			gp->mii_phy_addr = i;
-			if (phy_read(gp, PHY_CTRL) != 0xffff)
+			if (phy_read(gp, MII_BMCR) != 0xffff)
 				break;
 		}
 		if (i == 32) {
@@ -1685,12 +1907,10 @@
 		}
 	}
 
-	gem_init_pause_thresholds(gp);
-
 	return 0;
 }
 
-static void gem_init_hw(struct gem *gp)
+static void gem_init_hw(struct gem *gp, int restart_link)
 {
 	/* On Apple's gmac, I initialize the PHY only after
 	 * setting up the chip. It appears the gigabit PHYs
@@ -1698,18 +1918,28 @@
 	 * the chip is not running, I suspect it might not
 	 * be clocked at that point. --BenH
 	 */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-		gem_check_invariants(gp);
-		gp->hw_running = 1;
-	}
-	gem_init_phy(gp);
+	if (restart_link)
+		gem_init_phy(gp);
 	gem_init_dma(gp);
 	gem_init_mac(gp);
+	gem_init_pause_thresholds(gp);
 
-	gp->timer_ticks = 0;
-	gp->lstate = aneg_wait;
-	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
-	add_timer(&gp->link_timer);
+	spin_lock_irq(&gp->lock);
+	if (restart_link) {
+		/* Default aneg parameters */
+		gp->timer_ticks = 0;
+		gp->lstate = link_down;
+
+		spin_unlock_irq(&gp->lock);
+
+		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+		gem_begin_auto_negotiation(gp, NULL);
+	} else {
+		if (gp->lstate == link_up)
+			gem_set_link_modes(gp);
+
+		spin_unlock_irq(&gp->lock);
+	}
 }
 
 #ifdef CONFIG_ALL_PPC
@@ -1717,10 +1947,10 @@
  * setup properly. There appear to be no need to restore the
  * base addresses.
  */
-static void
-gem_apple_powerup(struct gem* gp)
+static void gem_apple_powerup(struct gem *gp)
 {
 	u16 cmd;
+	u32 mif_cfg;
 
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
 
@@ -1731,31 +1961,162 @@
     	pci_write_config_word(gp->pdev, PCI_COMMAND, cmd);
     	pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6);
     	pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8);
+
+	mdelay(1);
+	
+	mif_cfg = readl(gp->regs + MIF_CFG);
+	mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1);
+	mif_cfg |= MIF_CFG_MDI0;
+	writel(mif_cfg, gp->regs + MIF_CFG);
+	writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+	writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+
+	mdelay(1);
 }
 
 /* Turn off the chip's clock */
-static void
-gem_apple_powerdown(struct gem* gp)
+static void gem_apple_powerdown(struct gem *gp)
 {
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
 }
+
+#endif /* CONFIG_ALL_PPC */
+
+static void gem_stop_phy(struct gem *gp)
+{
+	u32 mifcfg;
+
+	if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
+		phy_write(gp, MII_BCM5201_INTERRUPT, 0);
+
+	/* Make sure we aren't polling PHY status change. We
+	 * don't currently use that feature though
+	 */
+	mifcfg = readl(gp->regs + MIF_CFG);
+	mifcfg &= ~MIF_CFG_POLL;
+	writel(mifcfg, gp->regs + MIF_CFG);
+
+	/* Here's a strange hack used by both MacOS 9 and X */
+	phy_write(gp, MII_LPA, phy_read(gp, MII_LPA));
+
+	if (gp->wake_on_lan) {
+		/* Setup wake-on-lan */
+	} else
+		writel(0, gp->regs + MAC_RXCFG);
+	writel(0, gp->regs + MAC_TXCFG);
+	writel(0, gp->regs + MAC_XIFCFG);
+	writel(0, gp->regs + TXDMA_CFG);
+	writel(0, gp->regs + RXDMA_CFG);
+
+	if (!gp->wake_on_lan) {
+		gem_stop(gp);
+		writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST);
+		writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
+		if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 ||
+		    gp->phy_mod == phymod_bcm5411) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+			phy_write(gp, MII_BMCR, BMCR_PDOWN);
+#endif
+		} else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+			u16 val = phy_read(gp, MII_BCM5201_AUXMODE2)
+			phy_write(gp, MII_BCM5201_AUXMODE2,
+				  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
+#endif				
+			phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+		}
+
+		/* According to Apple, we must set the MDIO pins to this begnign
+		 * state or we may 1) eat more current, 2) damage some PHYs
+		 */
+		writel(mifcfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG);
+		writel(0, gp->regs + MIF_BBCLK);
+		writel(0, gp->regs + MIF_BBDATA);
+		writel(0, gp->regs + MIF_BBOENAB);
+		writel(MAC_XIFCFG_GMII | MAC_XIFCFG_LBCK, gp->regs + MAC_XIFCFG);
+		(void) readl(gp->regs + MAC_XIFCFG);
+	}
+}
+
+/* Shut down the chip, must be called with pm_sem held.  */
+static void gem_shutdown(struct gem *gp)
+{
+	/* Make us not-running to avoid timers respawning */
+	gp->hw_running = 0;
+
+	/* Stop the link timer */
+	del_timer_sync(&gp->link_timer);
+
+	/* Stop the reset task */
+	while (gp->reset_task_pending)
+		schedule();
+	
+	/* Actually stop the chip */
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gem_stop_phy(gp);
+	else
+		gem_stop(gp);
+
+#ifdef CONFIG_ALL_PPC
+	/* Power down the chip */
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gem_apple_powerdown(gp);
 #endif /* CONFIG_ALL_PPC */
+}
+
+static void gem_pm_task(void *data)
+{
+	struct gem *gp = (struct gem *) data;
+
+	/* We assume if we can't lock the pm_sem, then open() was
+	 * called again (or suspend()), and we can safely ignore
+	 * the PM request
+	 */
+	if (down_trylock(&gp->pm_sem))
+		return;
+
+	/* Driver was re-opened or already shut down */
+	if (gp->opened || !gp->hw_running) {
+		up(&gp->pm_sem);
+		return;
+	}
+
+	gem_shutdown(gp);
+
+	up(&gp->pm_sem);
+}
+
+static void gem_pm_timer(unsigned long data)
+{
+	struct gem *gp = (struct gem *) data;
+
+	schedule_task(&gp->pm_task);
+}
 
 static int gem_open(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
-	unsigned long regs = gp->regs;
+	int hw_was_up = gp->hw_running;
 
-	del_timer(&gp->link_timer);
+	down(&gp->pm_sem);
 
+	/* Stop the PM timer/task */
+	del_timer(&gp->pm_timer);
+	flush_scheduled_tasks();
+
+	if (!gp->hw_running) {
 #ifdef CONFIG_ALL_PPC
-	/* First, we need to bring up the chip */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-		gem_apple_powerup(gp);
+		/* First, we need to bring up the chip */
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+			gem_apple_powerup(gp);
+			gem_check_invariants(gp);
+		}
 #endif /* CONFIG_ALL_PPC */
+		/* Reset the chip */
+		gem_stop(gp);
 
-	/* Reset the chip */
-	gem_stop(gp, regs);
+		gp->hw_running = 1;
+	}
 
 	/* We can now request the interrupt as we know it's masked
 	 * on the controller
@@ -1763,9 +2124,14 @@
 	if (request_irq(gp->pdev->irq, gem_interrupt,
 			SA_SHIRQ, dev->name, (void *)dev)) {
 #ifdef CONFIG_ALL_PPC
-		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			gem_apple_powerdown(gp);
 #endif /* CONFIG_ALL_PPC */
+		/* Fire the PM timer that will shut us down in about 10 seconds */
+		gp->pm_timer.expires = jiffies + 10*HZ;
+		add_timer(&gp->pm_timer);
+		up(&gp->pm_sem);
+
 		return -EAGAIN;
 	}
 
@@ -1773,7 +2139,11 @@
 	gem_init_rings(gp, 0);
 
 	/* Init & setup chip hardware */
-	gem_init_hw(gp);
+	gem_init_hw(gp, !hw_was_up);
+
+	gp->opened = 1;
+
+	up(&gp->pm_sem);
 
 	return 0;
 }
@@ -1782,17 +2152,110 @@
 {
 	struct gem *gp = dev->priv;
 
-	del_timer(&gp->link_timer);
-	gem_stop(gp, gp->regs);
+	/* Make sure we don't get distracted by suspend/resume */
+	down(&gp->pm_sem);
+
+	/* Stop traffic, mark us closed */
+	spin_lock_irq(&gp->lock);
+
+	gp->opened = 0;	
+	writel(0xffffffff, gp->regs + GREG_IMASK);
+	netif_stop_queue(dev);
+
+	spin_unlock_irq(&gp->lock);
+
+	/* Stop chip */
+	gem_stop(gp);
+
+	/* Get rid of rings */
 	gem_clean_rings(gp);
-	gp->hw_running = 0;
+
+	/* Bye, the pm timer will finish the job */
+	free_irq(gp->pdev->irq, (void *) dev);
+
+	/* Fire the PM timer that will shut us down in about 10 seconds */
+	gp->pm_timer.expires = jiffies + 10*HZ;
+	add_timer(&gp->pm_timer);
+
+	up(&gp->pm_sem);
+	
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gem_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct gem *gp = dev->priv;
+
+	/* We hold the PM semaphore during entire driver
+	 * sleep time
+	 */
+	down(&gp->pm_sem);
+
+	printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
+	       dev->name, gp->wake_on_lan ? "enabled" : "disabled");
+	
+	/* If the driver is opened, we stop the DMA */
+	if (gp->opened) {
+		/* Stop traffic, mark us closed */
+		netif_device_detach(dev);
+
+		spin_lock_irq(&gp->lock);
+
+		writel(0xffffffff, gp->regs + GREG_IMASK);
+
+		spin_unlock_irq(&gp->lock);
+
+		/* Stop chip */
+		gem_stop(gp);
+
+		/* Get rid of ring buffers */
+		gem_clean_rings(gp);
+
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+			disable_irq(gp->pdev->irq);
+	}
+
+	if (gp->hw_running) {
+		/* Kill PM timer if any */
+		del_timer_sync(&gp->pm_timer);
+		flush_scheduled_tasks();
+
+		gem_shutdown(gp);
+	}
+
+	return 0;
+}
+
+static int gem_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct gem *gp = dev->priv;
+
+	printk(KERN_INFO "%s: resuming\n", dev->name);
+
+	if (gp->opened) {
 #ifdef CONFIG_ALL_PPC
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-		gem_apple_powerdown(gp);
+		/* First, we need to bring up the chip */
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+			gem_apple_powerup(gp);
+			gem_check_invariants(gp);
+		}
 #endif /* CONFIG_ALL_PPC */
-	free_irq(gp->pdev->irq, (void *)dev);
+		gem_stop(gp);
+		gp->hw_running = 1;
+		gem_init_rings(gp, 0);
+		gem_init_hw(gp, 1);
+		netif_device_attach(dev);
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+			enable_irq(gp->pdev->irq);
+	}
+	up(&gp->pm_sem);
+
 	return 0;
 }
+#endif /* CONFIG_PM */
 
 static struct net_device_stats *gem_get_stats(struct net_device *dev)
 {
@@ -1908,12 +2371,219 @@
 		writel(hash_table[15], gp->regs + MAC_HASH15);
 	}
 
+	/* Hrm... we may walk on the reset task here... */
 	netif_wake_queue(dev);
 }
 
+/* Eventually add support for changing the advertisement
+ * on autoneg.
+ */
+static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
+{
+	struct gem *gp = dev->priv;
+	u16 bmcr;
+	int full_duplex, speed, pause;
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
+		return -EFAULT;
+		
+	switch(ecmd.cmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { cmd: ETHTOOL_GDRVINFO };
+
+		strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
+		strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
+		info.fw_version[0] = '\0';
+		strncpy(info.bus_info, gp->pdev->slot_name, ETHTOOL_BUSINFO_LEN);
+		info.regdump_len = 0; /*SUNGEM_NREGS;*/
+
+		if (copy_to_user(ep_user, &info, sizeof(info)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	case ETHTOOL_GSET:
+		ecmd.supported =
+			(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+			 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+			 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+		if (gp->gigabit_capable)
+			ecmd.supported |=
+				(SUPPORTED_1000baseT_Half |
+				 SUPPORTED_1000baseT_Full);
+
+		/* XXX hardcoded stuff for now */
+		ecmd.port = PORT_MII;
+		ecmd.transceiver = XCVR_EXTERNAL;
+		ecmd.phy_address = 0; /* XXX fixed PHYAD */
+
+		/* Record PHY settings if HW is on. */
+		if (gp->hw_running) {
+			bmcr = phy_read(gp, MII_BMCR);
+			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
+		} else
+			bmcr = 0;
+		if (bmcr & BMCR_ANENABLE) {
+			ecmd.autoneg = AUTONEG_ENABLE;
+			ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+		} else {
+			ecmd.autoneg = AUTONEG_DISABLE;
+			ecmd.speed =
+				(bmcr & BMCR_SPEED100) ?
+				SPEED_100 : SPEED_10;
+			ecmd.duplex =
+				(bmcr & BMCR_FULLDPLX) ?
+				DUPLEX_FULL : DUPLEX_HALF;
+		}
+		if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+
+	case ETHTOOL_SSET:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Verify the settings we care about. */
+		if (ecmd.autoneg != AUTONEG_ENABLE &&
+		    ecmd.autoneg != AUTONEG_DISABLE)
+			return -EINVAL;
+
+		if (ecmd.autoneg == AUTONEG_DISABLE &&
+		    ((ecmd.speed != SPEED_100 &&
+		      ecmd.speed != SPEED_10) ||
+		     (ecmd.duplex != DUPLEX_HALF &&
+		      ecmd.duplex != DUPLEX_FULL)))
+			return -EINVAL;
+
+		/* Apply settings and restart link process */
+		if (gp->hw_running)
+			del_timer(&gp->link_timer);
+		gem_begin_auto_negotiation(gp, &ecmd);
+		return 0;
+
+	case ETHTOOL_NWAY_RST:
+		if ((gp->link_cntl & BMCR_ANENABLE) == 0)
+			return -EINVAL;
+		if (gp->hw_running)
+			del_timer(&gp->link_timer);
+		gem_begin_auto_negotiation(gp, NULL);
+		return 0;
+
+	case ETHTOOL_GWOL:
+	case ETHTOOL_SWOL:
+		break; /* todo */
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { cmd: ETHTOOL_GLINK };
+
+		edata.data = (gp->lstate == link_up);
+		if (copy_to_user(ep_user, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL };
+
+		edata.data = gem_debug;
+		if (copy_to_user(ep_user, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+
+		if (copy_from_user(&edata, ep_user, sizeof(edata)))
+			return -EFAULT;
+		gem_debug = edata.data;
+		return 0;
+	}
+
+#if 0
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs regs;
+		u32 *regbuf;
+		int r = 0;
+
+		if (copy_from_user(&regs, useraddr, sizeof(regs)))
+			return -EFAULT;
+		
+		if (regs.len > SUNGEM_NREGS) {
+			regs.len = SUNGEM_NREGS;
+		}
+		regs.version = 0;
+		if (copy_to_user(useraddr, &regs, sizeof(regs)))
+			return -EFAULT;
+
+		if (!gp->hw_running)
+			return -ENODEV;
+		useraddr += offsetof(struct ethtool_regs, data);
+
+		/* Use kmalloc to avoid bloating the stack */
+		regbuf = kmalloc(4 * SUNGEM_NREGS, GFP_KERNEL);
+		if (!regbuf)
+			return -ENOMEM;
+		spin_lock_irq(&np->lock);
+		gem_get_regs(gp, regbuf);
+		spin_unlock_irq(&np->lock);
+
+		if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32)))
+			r = -EFAULT;
+		kfree(regbuf);
+		return r;
+	}
+#endif	
+	};
+
+	return -EOPNOTSUPP;
+}
+
 static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	return -EINVAL;
+	struct gem *gp = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	int rc = -EOPNOTSUPP;
+	
+	/* Hold the PM semaphore while doing ioctl's or we may collide
+	 * with open/close and power management and oops.
+	 */
+	down(&gp->pm_sem);
+	
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = gem_ethtool_ioctl(dev, ifr->ifr_data);
+		break;
+
+	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
+		data->phy_id = gp->mii_phy_addr;
+		/* Fallthrough... */
+
+	case SIOCGMIIREG:		/* Read MII PHY register. */
+		data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f);
+		rc = 0;
+		break;
+
+	case SIOCSMIIREG:		/* Write MII PHY register. */
+		if (!capable(CAP_NET_ADMIN)) {
+			rc = -EPERM;
+		} else {
+			__phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f);
+			rc = 0;
+		}
+		break;
+	};
+
+	up(&gp->pm_sem);
+	
+	return rc;
 }
 
 static int __devinit gem_get_device_address(struct gem *gp)
@@ -2030,6 +2700,26 @@
 	gp->dev = dev;
 
 	spin_lock_init(&gp->lock);
+	init_MUTEX(&gp->pm_sem);
+
+	init_timer(&gp->link_timer);
+	gp->link_timer.function = gem_link_timer;
+	gp->link_timer.data = (unsigned long) gp;
+
+	init_timer(&gp->pm_timer);
+	gp->pm_timer.function = gem_pm_timer;
+	gp->pm_timer.data = (unsigned long) gp;
+
+	INIT_TQUEUE(&gp->pm_task, gem_pm_task, gp);
+	INIT_TQUEUE(&gp->reset_task, gem_reset_task, gp);
+	
+	/* Default link parameters */
+	if (link_mode >= 0 && link_mode <= 6)
+		gp->link_cntl = link_modes[link_mode];
+	else
+		gp->link_cntl = BMCR_ANENABLE;
+	gp->lstate = link_down;
+	gp->timer_ticks = 0;
 
 	gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len);
 	if (gp->regs == 0UL) {
@@ -2038,9 +2728,26 @@
 		goto err_out_free_mmio_res;
 	}
 
-	/* On Apple's, we might not access the hardware at that point */
+	/* On Apple, we power the chip up now in order for check
+	 * invariants to work, but also because the firmware might
+	 * not have properly shut down the PHY.
+	 */
+#ifdef CONFIG_ALL_PPC
+	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+		gem_apple_powerup(gp);
+		if (gem_check_invariants(gp))
+			goto err_out_iounmap;
+		gem_stop(gp);
+		gp->hw_running = 1;
+		gem_init_phy(gp);
+		gem_begin_auto_negotiation(gp, NULL);
+	}
+#endif
+	/* Non Apple hardware, we just reset the chip and check
+	 * for invariants
+	 */
 	if (pdev->vendor != PCI_VENDOR_ID_APPLE) {
-		gem_stop(gp, gp->regs);
+		gem_stop(gp);
 		if (gem_check_invariants(gp))
 			goto err_out_iounmap;
 		gp->hw_running = 1;
@@ -2074,10 +2781,6 @@
 		       i == 5 ? ' ' : ':');
 	printk("\n");
 
-	init_timer(&gp->link_timer);
-	gp->link_timer.function = gem_link_timer;
-	gp->link_timer.data = (unsigned long) gp;
-
 	dev->open = gem_open;
 	dev->stop = gem_close;
 	dev->hard_start_xmit = gem_start_xmit;
@@ -2095,9 +2798,20 @@
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
 
+	/* Fire the PM timer that will shut us down in about 10 seconds */
+	gp->pm_timer.expires = jiffies + 10*HZ;
+	add_timer(&gp->pm_timer);
+
 	return 0;
 
 err_out_iounmap:
+	down(&gp->pm_sem);
+	/* Stop the PM timer & task */
+	del_timer_sync(&gp->pm_timer);
+	flush_scheduled_tasks();
+	if (gp->hw_running)
+		gem_shutdown(gp);
+	up(&gp->pm_sem);
 	iounmap((void *) gp->regs);
 
 err_out_free_mmio_res:
@@ -2120,6 +2834,14 @@
 
 		unregister_netdev(dev);
 
+		down(&gp->pm_sem);
+		/* Stop the PM timer & task */
+		del_timer_sync(&gp->pm_timer);
+		flush_scheduled_tasks();
+		if (gp->hw_running)
+			gem_shutdown(gp);
+		up(&gp->pm_sem);
+
 		pci_free_consistent(pdev,
 				    sizeof(struct gem_init_block),
 				    gp->init_block,
@@ -2127,9 +2849,6 @@
 		iounmap((void *) gp->regs);
 		release_mem_region(pci_resource_start(pdev, 0),
 				   pci_resource_len(pdev, 0));
-#ifdef CONFIG_ALL_PPC
-		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
-#endif		
 		kfree(dev);
 
 		pci_set_drvdata(pdev, NULL);
@@ -2140,7 +2859,11 @@
 	name:		GEM_MODULE_NAME,
 	id_table:	gem_pci_tbl,
 	probe:		gem_init_one,
-	remove:		gem_remove_one,
+	remove:		__devexit_p(gem_remove_one),
+#ifdef CONFIG_PM
+	suspend:	gem_suspend,
+	resume:		gem_resume,
+#endif /* CONFIG_PM */
 };
 
 static int __init gem_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/sungem.h linux/drivers/net/sungem.h
--- linux-2.4.16/drivers/net/sungem.h	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/sungem.h	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.8 2001/10/17 05:55:39 davem Exp $
+/* $Id: sungem.h,v 1.10 2001/11/29 03:57:33 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -753,64 +753,38 @@
 #define PROM_SIZE	0x0fffffUL	/* Size of ROM			*/
 #define PROM_END	0x200000UL	/* End of ROM			*/
 
-/* MII phy registers */
-#define PHY_CTRL	0x00
-#define PHY_STAT	0x01
-#define PHY_ID0		0x02
-#define PHY_ID1		0x03
-#define PHY_ADV		0x04
-#define PHY_LPA		0x05
-
-#define PHY_CTRL_SPD2	0x0040		/* Gigabit enable? (bcm5411)	*/
-#define PHY_CTRL_FDPLX	0x0100		/* Full duplex			*/
-#define PHY_CTRL_ISO	0x0400		/* Isloate MII from PHY		*/
-#define PHY_CTRL_ANRES	0x0200		/* Auto-negotiation restart	*/
-#define PHY_CTRL_ANENAB	0x1000		/* Auto-negotiation enable	*/
-#define PHY_CTRL_SPD100	0x2000		/* Select 100Mbps		*/
-#define PHY_CTRL_RST	0x8000		/* Reset PHY			*/
-
-#define PHY_STAT_LSTAT	0x0004		/* Link status			*/
-#define PHY_STAT_ANEGC	0x0020		/* Auto-negotiation complete	*/
-
-#define PHY_ADV_10HALF	0x0020
-#define PHY_ADV_10FULL	0x0040
-#define PHY_ADV_100HALF	0x0080
-#define PHY_ADV_100FULL	0x0100
-
-#define PHY_LPA_10HALF	0x0020
-#define PHY_LPA_10FULL	0x0040
-#define PHY_LPA_100HALF	0x0080
-#define PHY_LPA_100FULL	0x0100
-#define PHY_LPA_PAUSE	0x0400
-#define PHY_LPA_FAULT	0x2000
+/* MII definitions missing from mii.h */
+
+#define BMCR_SPD2	0x0040		/* Gigabit enable? (bcm5411)	*/
+#define LPA_PAUSE	0x0400
 
 /* More PHY registers (specific to Broadcom models) */
 
 /* MII BCM5201 MULTIPHY interrupt register */
-#define PHY_BCM5201_INTERRUPT			0x1A
-#define PHY_BCM5201_INTERRUPT_INTENABLE		0x4000
+#define MII_BCM5201_INTERRUPT			0x1A
+#define MII_BCM5201_INTERRUPT_INTENABLE		0x4000
 
-#define PHY_BCM5201_AUXMODE2			0x1B
-#define PHY_BCM5201_AUXMODE2_LOWPOWER		0x0008
+#define MII_BCM5201_AUXMODE2			0x1B
+#define MII_BCM5201_AUXMODE2_LOWPOWER		0x0008
 
-#define PHY_BCM5201_MULTIPHY                    0x1E
+#define MII_BCM5201_MULTIPHY                    0x1E
 
 /* MII BCM5201 MULTIPHY register bits */
-#define PHY_BCM5201_MULTIPHY_SERIALMODE         0x0002
-#define PHY_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
+#define MII_BCM5201_MULTIPHY_SERIALMODE         0x0002
+#define MII_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
 
 /* MII BCM5400 1000-BASET Control register */
-#define PHY_BCM5400_GB_CONTROL			0x09
-#define PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
+#define MII_BCM5400_GB_CONTROL			0x09
+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
 
 /* MII BCM5400 AUXCONTROL register */
-#define PHY_BCM5400_AUXCONTROL                  0x18
-#define PHY_BCM5400_AUXCONTROL_PWR10BASET       0x0004
+#define MII_BCM5400_AUXCONTROL                  0x18
+#define MII_BCM5400_AUXCONTROL_PWR10BASET       0x0004
 
 /* MII BCM5400 AUXSTATUS register */
-#define PHY_BCM5400_AUXSTATUS                   0x19
-#define PHY_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
-#define PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
+#define MII_BCM5400_AUXSTATUS                   0x19
+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
 
 /* When it can, GEM internally caches 4 aligned TX descriptors
  * at a time, so that it can use full cacheline DMA reads.
@@ -936,9 +910,21 @@
 
 #define RX_COPY_THRESHOLD  256
 
+#if TX_RING_SIZE < 128
+#define INIT_BLOCK_TX_RING_SIZE		128
+#else
+#define INIT_BLOCK_TX_RING_SIZE		TX_RING_SIZE
+#endif
+
+#if RX_RING_SIZE < 128
+#define INIT_BLOCK_RX_RING_SIZE		128
+#else
+#define INIT_BLOCK_RX_RING_SIZE		RX_RING_SIZE
+#endif
+
 struct gem_init_block {
-	struct gem_txd	txd[TX_RING_SIZE];
-	struct gem_rxd	rxd[RX_RING_SIZE];
+	struct gem_txd	txd[INIT_BLOCK_TX_RING_SIZE];
+	struct gem_rxd	rxd[INIT_BLOCK_RX_RING_SIZE];
 };
 
 enum gem_phy_type {
@@ -958,9 +944,12 @@
 };
 
 enum link_state {
-	aneg_wait,
-	force_wait,
-	aneg_up,
+	link_down = 0,	/* No link, will retry */
+	link_aneg,	/* Autoneg in progress */
+	link_force_try,	/* Try Forced link speed */
+	link_force_ret,	/* Forced mode worked, retrying autoneg */
+	link_force_ok,	/* Stay in forced mode */
+	link_up		/* Link is up */
 };
 
 struct gem {
@@ -973,6 +962,10 @@
 	 * (ie. not power managed)
 	 */
 	int hw_running;
+	int opened;
+	struct semaphore pm_sem;
+	struct tq_struct pm_task;
+	struct timer_list pm_timer;
 
 	struct gem_init_block *init_block;
 
@@ -988,14 +981,22 @@
 	int			rx_pause_off;
 	int			rx_pause_on;
 	int			mii_phy_addr;
+	int			gigabit_capable;
 
+	/* Autoneg & PHY control */
+	int			link_cntl;
+	int			link_advertise;
+	int			link_fcntl;
+	enum link_state		lstate;
+	struct timer_list	link_timer;
+	int			timer_ticks;
+	int			wake_on_lan;
+	struct tq_struct	reset_task;
+	volatile int		reset_task_pending;
+	
 	/* Diagnostic counters and state. */
 	u64 pause_entered;
 	u16 pause_last_time_recvd;
-
-	struct timer_list link_timer;
-	int timer_ticks;
-	enum link_state lstate;
 
 	dma_addr_t gblock_dvma;
 	struct pci_dev *pdev;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/tlan.c linux/drivers/net/tlan.c
--- linux-2.4.16/drivers/net/tlan.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/tlan.c	Fri Dec  7 18:08:43 2001
@@ -430,7 +430,7 @@
 	name:		"tlan",
 	id_table:	tlan_pci_tbl,
 	probe:		tlan_init_one,
-	remove:		tlan_remove_one,	
+	remove:		__devexit_p(tlan_remove_one),	
 };
 
 static int __init tlan_probe(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.16/drivers/net/tokenring/lanstreamer.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/tokenring/lanstreamer.c	Fri Dec  7 18:08:43 2001
@@ -1812,7 +1812,7 @@
   name:       "lanstreamer",
   id_table:   streamer_pci_tbl,
   probe:      streamer_init_one,
-  remove:     streamer_remove_one,
+  remove:     __devexit_p(streamer_remove_one),
 };
 
 static int __init streamer_init_module(void) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- linux-2.4.16/drivers/net/tokenring/olympic.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/tokenring/olympic.c	Fri Dec  7 18:08:43 2001
@@ -1705,7 +1705,7 @@
 	name:		"olympic",
 	id_table:	olympic_pci_tbl,
 	probe:		olympic_probe,
-	remove:		olympic_remove_one
+	remove:		__devexit_p(olympic_remove_one),
 };
 
 static int __init olympic_pci_init(void) 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- linux-2.4.16/drivers/net/tulip/tulip_core.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/tulip/tulip_core.c	Fri Dec  7 18:08:43 2001
@@ -1889,7 +1889,7 @@
 	name:		DRV_NAME,
 	id_table:	tulip_pci_tbl,
 	probe:		tulip_init_one,
-	remove:		tulip_remove_one,
+	remove:		__devexit_p(tulip_remove_one),
 #ifdef CONFIG_PM
 	suspend:	tulip_suspend,
 	resume:		tulip_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- linux-2.4.16/drivers/net/via-rhine.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/via-rhine.c	Fri Dec  7 18:08:43 2001
@@ -1667,7 +1667,7 @@
 	name:		"via-rhine",
 	id_table:	via_rhine_pci_tbl,
 	probe:		via_rhine_init_one,
-	remove:		via_rhine_remove_one,
+	remove:		__devexit_p(via_rhine_remove_one),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/wan/comx-hw-mixcom.c linux/drivers/net/wan/comx-hw-mixcom.c
--- linux-2.4.16/drivers/net/wan/comx-hw-mixcom.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/wan/comx-hw-mixcom.c	Tue Dec  4 19:25:30 2001
@@ -566,8 +566,6 @@
 
 	return 0;
 	
-err_restore_flags:
-	restore_flags(flags);
 err_release_region:
 	release_region(dev->base_addr, MIXCOM_IO_EXTENT);
 err_ret:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/wan/farsync.c linux/drivers/net/wan/farsync.c
--- linux-2.4.16/drivers/net/wan/farsync.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/wan/farsync.c	Fri Dec  7 18:08:43 2001
@@ -1810,7 +1810,7 @@
         name:           FST_NAME,
         id_table:       fst_pci_dev_id,
         probe:          fst_add_one,
-        remove:         fst_remove_one,
+        remove:         __devexit_p(fst_remove_one),
         suspend:        NULL,
         resume:         NULL,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c
--- linux-2.4.16/drivers/net/winbond-840.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/winbond-840.c	Fri Dec  7 18:08:43 2001
@@ -1697,7 +1697,7 @@
 	name:		DRV_NAME,
 	id_table:	w840_pci_tbl,
 	probe:		w840_probe1,
-	remove:		w840_remove1,
+	remove:		__devexit_p(w840_remove1),
 #ifdef CONFIG_PM
 	suspend:	w840_suspend,
 	resume:		w840_resume,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c
--- linux-2.4.16/drivers/net/wireless/airo.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/wireless/airo.c	Fri Dec  7 18:08:43 2001
@@ -64,7 +64,7 @@
 	name:     "airo",
 	id_table: card_ids,
 	probe:    airo_pci_probe,
-	remove:   airo_pci_remove,
+	remove:   __devexit_p(airo_pci_remove),
 };
 #endif /* CONFIG_PCI */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/wireless/orinoco_plx.c linux/drivers/net/wireless/orinoco_plx.c
--- linux-2.4.16/drivers/net/wireless/orinoco_plx.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/wireless/orinoco_plx.c	Fri Dec  7 18:08:43 2001
@@ -279,7 +279,7 @@
 	name:"orinoco_plx",
 	id_table:orinoco_plx_pci_id_table,
 	probe:orinoco_plx_init_one,
-	remove:orinoco_plx_remove_one,
+	remove:__devexit_p(orinoco_plx_remove_one),
 	suspend:0,
 	resume:0
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- linux-2.4.16/drivers/net/yellowfin.c	Mon Nov 26 10:35:01 2001
+++ linux/drivers/net/yellowfin.c	Fri Dec  7 18:08:43 2001
@@ -1506,7 +1506,7 @@
 	name:		DRV_NAME,
 	id_table:	yellowfin_pci_tbl,
 	probe:		yellowfin_init_one,
-	remove:		yellowfin_remove_one,
+	remove:		__devexit_p(yellowfin_remove_one),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- linux-2.4.16/drivers/parport/ChangeLog	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/ChangeLog	Mon Dec 10 18:03:11 2001
@@ -1,3 +1,33 @@
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* ieee1284_ops.c (parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr): Actually do something useful.
+
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (dmaval): Don't use DMA by default.  It seems to be
+	too buggy at the moment.  Use 'dma=auto' to restore the previous
+	behaviour.
+
+2001-12-03  Rich Liu  <Rich.Liu@ite.com.tw>
+
+	* parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port
+	serial board, not a serial+parallel.
+
+2001-11-30  Niels Kristian Bech Jensen  <nkbj@image.dk>
+
+	* parport_pc.c: Fix compiler warning.
+
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* daisy.c (DEBUG): Undefine.
+
+2001-12-06  Tim Waugh  <twaugh@redhat.com>
+
+	* ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
+	PARPORT_CONTROL_AUTOFD as well.  Bug spotted by Joe
+	<joeja@mindspring.com>.
+
 2001-11-12  Tim Waugh  <twaugh@redhat.com>
 
 	* parport_pc.c (init_module): Warn when parameters are ignored.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/Config.in linux/drivers/parport/Config.in
--- linux-2.4.16/drivers/parport/Config.in	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/Config.in	Thu Dec  6 16:12:19 2001
@@ -24,9 +24,13 @@
          bool '    Use FIFO/DMA if available (EXPERIMENTAL)' CONFIG_PARPORT_PC_FIFO
          bool '    SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
       fi
-   fi
-   if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
-	 dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
+      if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+         if [ "$CONFIG_PARPORT_PC" = "y" ]; then
+            dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
+         else
+            dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PARPORT_PC
+         fi
+      fi
    fi
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/daisy.c linux/drivers/parport/daisy.c
--- linux-2.4.16/drivers/parport/daisy.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/daisy.c	Fri Dec  7 19:41:06 2001
@@ -23,7 +23,7 @@
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 
-#define DEBUG /* undef me for production */
+#undef DEBUG /* undef me for production */
 
 #ifdef DEBUG
 #define DPRINTK(stuff...) printk (stuff)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- linux-2.4.16/drivers/parport/ieee1284_ops.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/ieee1284_ops.c	Fri Dec  7 19:41:06 2001
@@ -514,7 +514,8 @@
 
 	/* Set HostAck low to start accepting data. */
 	ctl = parport_read_control (port);
-	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
+	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT |
+		 PARPORT_CONTROL_AUTOFD);
 	parport_write_control (port,
 			       ctl | PARPORT_CONTROL_AUTOFD);
 	while (count < len) {
@@ -823,35 +824,40 @@
 					const void *buffer, size_t len,
 					int flags)
 {
-	/* This is untested */
 	unsigned char *bp = (unsigned char *) buffer;
 	size_t ret = 0;
 
+	/* set EPP idle state (just to make sure) with strobe low */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
 			      PARPORT_CONTROL_SELECT |
-			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_INIT,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT);
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_forward (port);
 	for (; len > 0; len--, bp++) {
-		/* Write data and assert nAStrb. */
+		/* Event 56: Write data and set nAStrb low. */
 		parport_write_data (port, *bp);
 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
 				      PARPORT_CONTROL_SELECT);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 58: wait for busy (nWait) to go high */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
 			break;
 
+		/* Event 59: set nAStrb high */
 		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for busy (nWait) to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY, 5))
 			break;
 
 		ret++;
 	}
 
+	/* Event 61: set strobe (nWrite) high */
 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 
 	return ret;
@@ -862,28 +868,36 @@
 				       void *buffer, size_t len,
 				       int flags)
 {
-	/* This is untested. */
 	unsigned char *bp = (unsigned char *) buffer;
 	unsigned ret = 0;
 
+	/* Set EPP idle state (just to make sure) with strobe high */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_AUTOFD, 0);
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_reverse (port);
 	for (; len > 0; len--, bp++) {
-		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		/* Event 64: set nSelectIn (nAStrb) low */
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
 
-		/* Event 58 */
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 58: wait for Busy to go high */
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
 			break;
+		}
 
 		*bp = parport_read_data (port);
 
+		/* Event 59: set nSelectIn (nAStrb) high */
 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
 				      PARPORT_CONTROL_SELECT);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for Busy to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 
+					     PARPORT_STATUS_BUSY, 5))
 			break;
 
 		ret++;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/parport_cs.c linux/drivers/parport/parport_cs.c
--- linux-2.4.16/drivers/parport/parport_cs.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/parport_cs.c	Tue Dec  4 19:25:30 2001
@@ -5,7 +5,7 @@
     (specifically, for the Quatech SPP-100 EPP card: other cards will
     probably require driver tweaks)
     
-    parport_cs.c 1.20 2000/11/02 23:15:05
+    parport_cs.c 1.24 2001/10/13 14:04:05
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -57,32 +57,31 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
+/*====================================================================*/
 
-#ifndef VERSION
-#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-#endif
+/* Module parameters */
 
-/*====================================================================*/
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA parallel port card driver");
+MODULE_LICENSE("Dual MPL/GPL");
 
-/* Parameters that can be set with 'insmod' */
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-static int epp_mode = 1;
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(epp_mode, "i");
+
+INT_MODULE_PARM(epp_mode, 1);
+
+#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 =
+"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -105,9 +104,6 @@
 static dev_info_t dev_info = "parport_cs";
 static dev_link_t *dev_list = NULL;
 
-extern struct parport_operations parport_pc_ops;
-static struct parport_operations parport_cs_ops;
-
 /*====================================================================*/
 
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -307,19 +303,6 @@
 	goto failed;
     }
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
-    p->private_data = kmalloc(sizeof(struct parport_pc_private),
-			      GFP_KERNEL);
-    ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c;
-#endif
-    parport_proc_register(p);
-    p->flags |= PARPORT_FLAG_COMA;
-    parport_pc_write_econtrol(p, 0x00);
-    parport_pc_write_control(p, 0x0c);
-    parport_pc_write_data(p, 0x00);
-#endif
-
     p->modes |= PARPORT_MODE_PCSPP;
     if (epp_mode)
 	p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
@@ -365,14 +348,8 @@
 
     if (info->ndev) {
 	struct parport *p = info->port;
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-	if (!(p->flags & PARPORT_FLAG_COMA))
-	    parport_quiesce(p);
-#endif
 	parport_proc_unregister(p);
-#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
 	kfree(p->private_data);
-#endif
 	parport_unregister_port(p);
     }
     info->ndev = 0;
@@ -430,24 +407,6 @@
 
 /*====================================================================*/
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-
-static void inc_use_count(void)
-{
-    MOD_INC_USE_COUNT;
-    parport_pc_ops.inc_use_count();
-}
-
-static void dec_use_count(void)
-{
-    MOD_DEC_USE_COUNT;
-    parport_pc_ops.dec_use_count();
-}
-
-#endif
-
-/*====================================================================*/
-
 static int __init init_parport_cs(void)
 {
     servinfo_t serv;
@@ -459,13 +418,6 @@
 	return -1;
     }
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-    /* This is to protect against unloading modules out of order */
-    parport_cs_ops = parport_pc_ops;
-    parport_cs_ops.inc_use_count = &inc_use_count;
-    parport_cs_ops.dec_use_count = &dec_use_count;
-#endif
-
     register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
     return 0;
 }
@@ -480,4 +432,3 @@
 
 module_init(init_parport_cs);
 module_exit(exit_parport_cs);
-MODULE_LICENSE("Dual MPL/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- linux-2.4.16/drivers/parport/parport_pc.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/parport_pc.c	Fri Dec  7 19:41:06 2001
@@ -91,7 +91,9 @@
 } superios[NR_SUPERIOS] __devinitdata = { {0,},};
 
 static int user_specified __devinitdata = 0;
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 static int verbose_probing;
+#endif
 static int registered_parport;
 
 /* frob_control, but for ECR */
@@ -1780,6 +1782,7 @@
 	return ok;
 }
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
 	int i;
@@ -1905,6 +1908,7 @@
 
 	return 1;
 }
+#endif
 
 static int __devinit parport_ECPPS2_supported(struct parport *pb)
 {
@@ -2004,7 +2008,9 @@
 
 /* Don't bother probing for modes we know we won't use. */
 static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+#endif
 static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
 static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
 static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
@@ -2453,9 +2459,8 @@
 		ite8872set = 0x64e00000;
 		break;
 	case 0x6:
-		printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n");
-		ite8872set = 0x64a00000;
-		break;
+		printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+		return 0;
 	case 0x8:
 		DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
 		return 0;
@@ -3007,7 +3012,7 @@
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int io_hi[PARPORT_PC_MAX_PORTS+1] =
 	{ [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
@@ -3024,8 +3029,10 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(verbose_probing, "i");
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
+MODULE_PARM(verbose_probing, "i");
+#endif
 
 int init_module(void)
 {	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/parport/parport_serial.c linux/drivers/parport/parport_serial.c
--- linux-2.4.16/drivers/parport/parport_serial.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/parport/parport_serial.c	Fri Dec  7 18:08:43 2001
@@ -331,7 +331,7 @@
 	name:		"parport_serial",
 	id_table:	parport_serial_pci_tbl,
 	probe:		parport_serial_pci_probe,
-	remove:		parport_serial_pci_remove,
+	remove:		__devexit_p(parport_serial_pci_remove),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c
--- linux-2.4.16/drivers/pcmcia/cistpl.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/pcmcia/cistpl.c	Tue Dec  4 19:25:30 2001
@@ -264,11 +264,11 @@
 	(s->cis_mem.sys_start == 0)) {
 	int low = !(s->cap.features & SS_CAP_PAGE_REGS);
 	vs = s;
-	validate_mem(cis_readable, checksum_match, low);
+	validate_mem(cis_readable, checksum_match, low, s);
 	s->cis_mem.sys_start = 0;
 	vs = NULL;
 	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
-			    s->cap.map_size, low, "card services")) {
+			    s->cap.map_size, low, "card services", s)) {
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
 	    return CS_OUT_OF_RESOURCE;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-2.4.16/drivers/pcmcia/cs.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/pcmcia/cs.c	Tue Dec  4 19:25:30 2001
@@ -809,7 +809,7 @@
 	    return 1;
     for (i = 0; i < MAX_IO_WIN; i++) {
 	if (s->io[i].NumPorts == 0) {
-	    if (find_io_region(base, num, align, name) == 0) {
+	    if (find_io_region(base, num, align, name, s) == 0) {
 		s->io[i].Attributes = attr;
 		s->io[i].BasePort = *base;
 		s->io[i].NumPorts = s->io[i].InUse = num;
@@ -821,7 +821,7 @@
 	/* Try to extend top of window */
 	try = s->io[i].BasePort + s->io[i].NumPorts;
 	if ((*base == 0) || (*base == try))
-	    if (find_io_region(&try, num, 0, name) == 0) {
+	    if (find_io_region(&try, num, 0, name, s) == 0) {
 		*base = try;
 		s->io[i].NumPorts += num;
 		s->io[i].InUse += num;
@@ -830,7 +830,7 @@
 	/* Try to extend bottom of window */
 	try = s->io[i].BasePort - num;
 	if ((*base == 0) || (*base == try))
-	    if (find_io_region(&try, num, 0, name) == 0) {
+	    if (find_io_region(&try, num, 0, name, s) == 0) {
 		s->io[i].BasePort = *base = try;
 		s->io[i].NumPorts += num;
 		s->io[i].InUse += num;
@@ -1974,7 +1974,7 @@
 	find_mem_region(&win->base, win->size, align,
 			(req->Attributes & WIN_MAP_BELOW_1MB) ||
 			!(s->cap.features & SS_CAP_PAGE_REGS),
-			(*handle)->dev_info))
+			(*handle)->dev_info, s))
 	return CS_IN_USE;
     (*handle)->state |= CLIENT_WIN_REQ(w);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- linux-2.4.16/drivers/pcmcia/cs_internal.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/pcmcia/cs_internal.h	Tue Dec  4 19:25:30 2001
@@ -238,11 +238,11 @@
 
 /* In rsrc_mgr */
 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low);
+		  int force_low, socket_info_t *s);
 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
-		   char *name);
+		   char *name, socket_info_t *s);
 int find_mem_region(u_long *base, u_long num, u_long align,
-		    int force_low, char *name);
+		    int force_low, char *name, socket_info_t *s);
 int try_irq(u_int Attributes, int irq, int specific);
 void undo_irq(u_int Attributes, int irq);
 int adjust_resource_info(client_handle_t handle, adjust_t *adj);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- linux-2.4.16/drivers/pcmcia/pci_socket.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/pcmcia/pci_socket.c	Fri Dec  7 18:08:43 2001
@@ -249,7 +249,7 @@
 	name:		"cardbus",
 	id_table:	cardbus_table,
 	probe:		cardbus_probe,
-	remove:		cardbus_remove,
+	remove:		__devexit_p(cardbus_remove),
 	suspend:	cardbus_suspend,
 	resume:		cardbus_resume,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- linux-2.4.16/drivers/pcmcia/rsrc_mgr.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/pcmcia/rsrc_mgr.c	Fri Dec  7 18:15:24 2001
@@ -44,6 +44,7 @@
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
+#include <linux/pci.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -103,8 +104,82 @@
 
 ======================================================================*/
 
-#define check_io_resource(b,n)	check_resource(&ioport_resource, (b), (n))
-#define check_mem_resource(b,n)	check_resource(&iomem_resource, (b), (n))
+static struct resource *resource_parent(unsigned long b, unsigned long n,
+					int flags, struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI
+	struct resource res, *pr;
+
+	if (dev != NULL) {
+		res.start = b;
+		res.end = b + n - 1;
+		res.flags = flags;
+		pr = pci_find_parent_resource(dev, &res);
+		if (pr)
+			return pr;
+	}
+#endif /* CONFIG_PCI */
+	if (flags & IORESOURCE_MEM)
+		return &iomem_resource;
+	return &ioport_resource;
+}
+
+static inline int check_io_resource(unsigned long b, unsigned long n,
+				    struct pci_dev *dev)
+{
+	return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n);
+}
+
+static inline int check_mem_resource(unsigned long b, unsigned long n,
+				     struct pci_dev *dev)
+{
+	return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n);
+}
+
+static struct resource *make_resource(unsigned long b, unsigned long n,
+				      int flags, char *name)
+{
+	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+
+	if (res) {
+		memset(res, 0, sizeof(*res));
+		res->name = name;
+		res->start = b;
+		res->end = b + n - 1;
+		res->flags = flags | IORESOURCE_BUSY;
+	}
+	return res;
+}
+
+static int request_io_resource(unsigned long b, unsigned long n,
+			       char *name, struct pci_dev *dev)
+{
+	struct resource *res = make_resource(b, n, IORESOURCE_IO, name);
+	struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev);
+	int err = -ENOMEM;
+
+	if (res) {
+		err = request_resource(pr, res);
+		if (err)
+			kfree(res);
+	}
+	return err;
+}
+
+static int request_mem_resource(unsigned long b, unsigned long n,
+				char *name, struct pci_dev *dev)
+{
+	struct resource *res = make_resource(b, n, IORESOURCE_MEM, name);
+	struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev);
+	int err = -ENOMEM;
+
+	if (res) {
+		err = request_resource(pr, res);
+		if (err)
+			kfree(res);
+	}
+	return err;
+}
 
 /*======================================================================
 
@@ -194,7 +269,7 @@
     }   
     memset(b, 0, 256);
     for (i = base, most = 0; i < base+num; i += 8) {
-	if (check_io_resource(i, 8))
+	if (check_io_resource(i, 8, NULL))
 	    continue;
 	hole = inb(i);
 	for (j = 1; j < 8; j++)
@@ -207,7 +282,7 @@
 
     bad = any = 0;
     for (i = base; i < base+num; i += 8) {
-	if (check_io_resource(i, 8))
+	if (check_io_resource(i, 8, NULL))
 	    continue;
 	for (j = 0; j < 8; j++)
 	    if (inb(i+j) != most) break;
@@ -247,7 +322,8 @@
 ======================================================================*/
 
 static int do_mem_probe(u_long base, u_long num,
-			int (*is_valid)(u_long), int (*do_cksum)(u_long))
+			int (*is_valid)(u_long), int (*do_cksum)(u_long),
+			socket_info_t *s)
 {
     u_long i, j, bad, fail, step;
 
@@ -258,13 +334,14 @@
     for (i = j = base; i < base+num; i = j + step) {
 	if (!fail) {	
 	    for (j = i; j < base+num; j += step)
-		if ((check_mem_resource(j, step) == 0) && is_valid(j))
+		if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
+		    is_valid(j))
 		    break;
 	    fail = ((i == base) && (j == base+num));
 	}
 	if (fail) {
 	    for (j = i; j < base+num; j += 2*step)
-		if ((check_mem_resource(j, 2*step) == 0) &&
+		if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) &&
 		    do_cksum(j) && do_cksum(j+step))
 		    break;
 	}
@@ -283,12 +360,12 @@
 
 static u_long inv_probe(int (*is_valid)(u_long),
 			int (*do_cksum)(u_long),
-			resource_map_t *m)
+			resource_map_t *m, socket_info_t *s)
 {
     u_long ok;
     if (m == &mem_db)
 	return 0;
-    ok = inv_probe(is_valid, do_cksum, m->next);
+    ok = inv_probe(is_valid, do_cksum, m->next, s);
     if (ok) {
 	if (m->base >= 0x100000)
 	    sub_interval(&mem_db, m->base, m->num);
@@ -296,11 +373,11 @@
     }
     if (m->base < 0x100000)
 	return 0;
-    return do_mem_probe(m->base, m->num, is_valid, do_cksum);
+    return do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
 }
 
 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low)
+		  int force_low, socket_info_t *s)
 {
     resource_map_t *m, *n;
     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
@@ -310,7 +387,7 @@
     if (!probe_mem) return;
     /* We do up to four passes through the list */
     if (!force_low) {
-	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
+	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
 	    return;
 	printk(KERN_NOTICE "cs: warning: no high memory space "
 	       "available!\n");
@@ -321,7 +398,7 @@
 	/* Only probe < 1 MB */
 	if (m->base >= 0x100000) continue;
 	if ((m->base | m->num) & 0xffff) {
-	    ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
+	    ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
 	    continue;
 	}
 	/* Special probe for 64K-aligned block */
@@ -331,7 +408,7 @@
 		if (ok >= mem_limit)
 		    sub_interval(&mem_db, b, 0x10000);
 		else
-		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
+		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s);
 	    }
 	}
     }
@@ -340,7 +417,7 @@
 #else /* CONFIG_ISA */
 
 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low)
+		  int force_low, socket_info_t *s)
 {
     resource_map_t *m;
     static int done = 0;
@@ -348,7 +425,7 @@
     if (!probe_mem || done++)
 	return;
     for (m = mem_db.next; m != &mem_db; m = m->next)
-	if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
+	if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s))
 	    return;
 }
 
@@ -368,7 +445,7 @@
 ======================================================================*/
 
 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
-		   char *name)
+		   char *name, socket_info_t *s)
 {
     ioaddr_t try;
     resource_map_t *m;
@@ -378,9 +455,8 @@
 	for (try = (try >= m->base) ? try : try+align;
 	     (try >= m->base) && (try+num <= m->base+m->num);
 	     try += align) {
-	    if (check_io_resource(try, num) == 0) {
+	    if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) {
 		*base = try;
-		request_region(try, num, name);
 		return 0;
 	    }
 	    if (!align) break;
@@ -390,7 +466,7 @@
 }
 
 int find_mem_region(u_long *base, u_long num, u_long align,
-		    int force_low, char *name)
+		    int force_low, char *name, socket_info_t *s)
 {
     u_long try;
     resource_map_t *m;
@@ -403,8 +479,7 @@
 	    for (try = (try >= m->base) ? try : try+align;
 		 (try >= m->base) && (try+num <= m->base+m->num);
 		 try += align) {
-		if (check_mem_resource(try, num) == 0) {
-		    request_mem_region(try, num, name);
+		if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) {
 		    *base = try;
 		    return 0;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- linux-2.4.16/drivers/pcmcia/yenta.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/pcmcia/yenta.c	Sun Dec  9 19:23:10 2001
@@ -688,7 +688,7 @@
 
 	/*
 	 * This does not work currently. The controller
-	 * loses too much informationduring D3 to come up
+	 * loses too much information during D3 to come up
 	 * cleanly. We should probably fix yenta_init()
 	 * to update all the critical registers, notably
 	 * the IO and MEM bridging region data.. That is
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- linux-2.4.16/drivers/scsi/BusLogic.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/BusLogic.c	Tue Dec  4 19:25:30 2001
@@ -4131,7 +4131,7 @@
   /*
     Attempt to read the first 1024 bytes from the disk device.
   */
-  BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, 1024);
+  BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, block_size(Device));
   if (BufferHead == NULL) return 0;
   /*
     If the boot sector partition table flag is valid, search for a partition
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- linux-2.4.16/drivers/scsi/Config.in	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/Config.in	Sun Dec  9 18:12:25 2001
@@ -50,6 +50,9 @@
 dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_tristate 'Adaptec AACRAID support (EXPERIMENTAL)' CONFIG_SCSI_AACRAID $CONFIG_SCSI $CONFIG_PCI
+fi
 source drivers/scsi/aic7xxx/Config.in
 if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
    dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- linux-2.4.16/drivers/scsi/Makefile	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/Makefile	Sun Dec  9 18:12:25 2001
@@ -25,6 +25,7 @@
 mod-subdirs	:= pcmcia ../acorn/scsi
 
 
+subdir-$(CONFIG_SCSI_AACRAID)	+= aacraid
 subdir-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx
 subdir-$(CONFIG_PCMCIA)		+= pcmcia
 
@@ -64,6 +65,9 @@
 obj-$(CONFIG_SCSI_AHA152X)	+= aha152x.o
 obj-$(CONFIG_SCSI_AHA1542)	+= aha1542.o
 obj-$(CONFIG_SCSI_AHA1740)	+= aha1740.o
+ifeq ($(CONFIG_SCSI_AACRAID),y)
+  obj-$(CONFIG_SCSI_AACRAID)	+= aacraid/aacraid.o
+endif
 ifeq ($(CONFIG_SCSI_AIC7XXX),y)
 obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx/aic7xxx_drv.o
 endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- linux-2.4.16/drivers/scsi/NCR5380.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/NCR5380.c	Fri Dec  7 19:47:12 2001
@@ -83,8 +83,6 @@
  *     basically, transfer size needs to be reduced by one 
  *     and the last byte read as is done with PSEUDO_DMA.
  * 
- * 3.  Test USLEEP code 
- *
  * 4.  Test SCSI-II tagged queueing (I have no devices which support 
  *      tagged queueing)
  *
@@ -110,6 +108,12 @@
 #define READ_OVERRUNS
 #endif
 
+#ifdef BOARD_REQUIRES_NO_DELAY
+#define io_recovery_delay(x)
+#else
+#define io_recovery_delay(x)	udelay(x)
+#endif
+
 /*
  * Design
  * Issues :
@@ -192,9 +196,8 @@
  * phase goes through the various phases as instructed by the target.
  * if the target goes into MSG IN and sends a DISCONNECT message,
  * the command structure is placed into the per instance disconnected
- * queue, and NCR5380_main tries to find more work.  If USLEEP
- * was defined, and the target is idle for too long, the system
- * will try to sleep.
+ * queue, and NCR5380_main tries to find more work.  If the target is 
+ * idle for too long, the system will try to sleep.
  *
  * If a command has disconnected, eventually an interrupt will trigger,
  * calling NCR5380_intr()  which will in turn call NCR5380_reselect
@@ -244,21 +247,14 @@
  *      rely on phase mismatch and EOP interrupts to determine end 
  *      of phase.
  *
- * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible
- *
  * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
  *          only really want to use this if you're having a problem with
  *          dropped characters during high speed communications, and even
  *          then, you're going to be better off twiddling with transfersize
  *          in the high level code.
  *
- * USLEEP - if defined, on devices that aren't disconnecting from the 
- *      bus, we will go to sleep so that the CPU can get real work done 
- *      when we run a command that won't complete immediately.
- *
- * Defaults for these will be provided if USLEEP is defined, although
- * the user may want to adjust these to allocate CPU resources to 
- * the SCSI driver or "real" code.
+ * Defaults for these will be provided although the user may want to adjust 
+ * these to allocate CPU resources to the SCSI driver or "real" code.
  * 
  * USLEEP_SLEEP - amount of time, in jiffies, to sleep
  *
@@ -322,18 +318,13 @@
 static void do_reset(struct Scsi_Host *host);
 static struct Scsi_Host *first_instance = NULL;
 static Scsi_Host_Template *the_template = NULL;
-
-#ifdef USLEEP
-struct timer_list usleep_timer;
-#endif
+static struct timer_list usleep_timer;
 
 /*
- * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *	initialize_SCp		-	init the scsi pointer field
+ *	@cmd: command block to set up
  *
- * Purpose : initialize the saved data pointers for cmd to point to the 
- *      start of the buffer.
- *
- * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ *	Set up the internal fields in the SCSI command.
  */
 
 static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
@@ -362,88 +353,49 @@
 static struct {
 	unsigned char mask;
 	const char *name;
-} signals[] = { {
-
-		SR_DBP, "PARITY"
-}, {
-	SR_RST, "RST"
-}, {
-	SR_BSY, "BSY"
-},
-{
-	SR_REQ, "REQ"
-}, {
-	SR_MSG, "MSG"
-}, {
-	SR_CD, "CD"
-}, {
-	SR_IO, "IO"
-},
-{
-	SR_SEL, "SEL"
-}, {
-	0, NULL
-}
-},
-
-basrs[] = { {
-		BASR_ATN, "ATN"
-}, {
-	BASR_ACK, "ACK"
-}, {
-	0, NULL
-}
-},
-
-icrs[] = { {
-		ICR_ASSERT_RST, "ASSERT RST"
-}, {
-	ICR_ASSERT_ACK, "ASSERT ACK"
-},
-{
-	ICR_ASSERT_BSY, "ASSERT BSY"
-}, {
-	ICR_ASSERT_SEL, "ASSERT SEL"
-},
-{
-	ICR_ASSERT_ATN, "ASSERT ATN"
-}, {
-	ICR_ASSERT_DATA, "ASSERT DATA"
-},
-{
-	0, NULL
-}
-},
-
-mrs[] = { {
-		MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"
-}, {
-	MR_TARGET, "MODE TARGET"
-},
-{
-	MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"
-}, {
-	MR_ENABLE_PAR_INTR,
-	    "MODE PARITY INTR"
-}, {
-	MR_MONITOR_BSY, "MODE MONITOR BSY"
-},
-{
-	MR_DMA_MODE, "MODE DMA"
-}, {
-	MR_ARBITRATE, "MODE ARBITRATION"
-},
-{
-	0, NULL
-}
+} signals[] = { 
+	{SR_DBP, "PARITY"}, 
+	{SR_RST, "RST"}, 
+	{SR_BSY, "BSY"}, 
+	{SR_REQ, "REQ"}, 
+	{SR_MSG, "MSG"}, 
+	{SR_CD, "CD"}, 
+	{SR_IO, "IO"}, 
+	{SR_SEL, "SEL"}, 
+	{0, NULL}
+}, 
+basrs[] = {
+	{BASR_ATN, "ATN"}, 
+	{BASR_ACK, "ACK"}, 
+	{0, NULL}
+}, 
+icrs[] = { 
+	{ICR_ASSERT_RST, "ASSERT RST"}, 
+	{ICR_ASSERT_ACK, "ASSERT ACK"}, 
+	{ICR_ASSERT_BSY, "ASSERT BSY"}, 
+	{ICR_ASSERT_SEL, "ASSERT SEL"}, 
+	{ICR_ASSERT_ATN, "ASSERT ATN"}, 
+	{ICR_ASSERT_DATA, "ASSERT DATA"}, 
+	{0, NULL}
+}, 
+mrs[] = { 
+	{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, 
+	{MR_TARGET, "MODE TARGET"}, 
+	{MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, 
+	{MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, 
+	{MR_MONITOR_BSY, "MODE MONITOR BSY"}, 
+	{MR_DMA_MODE, "MODE DMA"}, 
+	{MR_ARBITRATE, "MODE ARBITRATION"}, 
+	{0, NULL}
 };
 
-/*
- * Function : void NCR5380_print(struct Scsi_Host *instance)
+/**
+ *	NCR5380_print	-	print scsi bus signals
+ *	@instance:	adapter state to dump
  *
- * Purpose : print the SCSI bus signals for debugging purposes
+ *	Print the SCSI bus signals for debugging purposes
  *
- * Input : instance - which NCR5380
+ *	Locks: none
  */
 
 static void NCR5380_print(struct Scsi_Host *instance)
@@ -452,6 +404,7 @@
 	unsigned long flags;
 	unsigned char status, data, basr, mr, icr, i;
 	NCR5380_setup(instance);
+	/* FIXME - this needs proper locking */
 	save_flags(flags);
 	cli();
 	data = NCR5380_read(CURRENT_SCSI_DATA_REG);
@@ -483,32 +436,22 @@
 	unsigned char value;
 	const char *name;
 } phases[] = {
-
-	{
-		PHASE_DATAOUT, "DATAOUT"
-	}, {
-		PHASE_DATAIN, "DATAIN"
-	}, {
-		PHASE_CMDOUT, "CMDOUT"
-	},
-	{
-		PHASE_STATIN, "STATIN"
-	}, {
-		PHASE_MSGOUT, "MSGOUT"
-	}, {
-		PHASE_MSGIN, "MSGIN"
-	},
-	{
-		PHASE_UNKNOWN, "UNKNOWN"
-	}
+	{PHASE_DATAOUT, "DATAOUT"}, 
+	{PHASE_DATAIN, "DATAIN"}, 
+	{PHASE_CMDOUT, "CMDOUT"}, 
+	{PHASE_STATIN, "STATIN"}, 
+	{PHASE_MSGOUT, "MSGOUT"}, 
+	{PHASE_MSGIN, "MSGIN"}, 
+	{PHASE_UNKNOWN, "UNKNOWN"}
 };
 
 /* 
- * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *	NCR5380_print_phase	-	show SCSI phase
+ *	@instance: adapter to dump
  *
- * Purpose : print the current SCSI phase for debugging purposes
+ * 	Print the current SCSI phase for debugging purposes
  *
- * Input : instance - which NCR5380
+ *	Locks: none
  */
 
 static void NCR5380_print_phase(struct Scsi_Host *instance)
@@ -520,11 +463,9 @@
 
 	status = NCR5380_read(STATUS_REG);
 	if (!(status & SR_REQ))
-		printk("scsi%d : REQ not asserted, phase unknown.\n",
-		       instance->host_no);
+		printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no);
 	else {
-		for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
-		     (phases[i].value != (status & PHASE_MASK)); ++i);
+		for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
 		printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
 	}
 }
@@ -549,7 +490,7 @@
  * conditions are possible.
  */
 
-static volatile int main_running = 0;
+static unsigned long main_running = 0;
 
 /* 
  * Function : run_main(void)
@@ -563,14 +504,10 @@
 
 static __inline__ void run_main(void)
 {
-	if (!main_running) {
-		main_running = 1;
+	if (!test_and_set_bit(0, &main_running))
 		NCR5380_main();
-	}
 }
 
-#ifdef USLEEP
-
 /*
  * These need tweaking, and would probably work best as per-device 
  * flags initialized differently for disk, tape, cd, etc devices.
@@ -621,63 +558,67 @@
 static int should_disconnect(unsigned char cmd)
 {
 	switch (cmd) {
-		case READ_6:
-		    case WRITE_6:
-		    case SEEK_6:
-		    case READ_10:
-		    case WRITE_10:
-		    case SEEK_10:
-		    return DISCONNECT_TIME_TO_DATA;
-		case FORMAT_UNIT:
-		    case SEARCH_HIGH:
-		    case SEARCH_LOW:
-		    case SEARCH_EQUAL:
-		    return DISCONNECT_LONG;
-		default:
-		    return DISCONNECT_NONE;
+	case READ_6:
+	case WRITE_6:
+	case SEEK_6:
+	case READ_10:
+	case WRITE_10:
+	case SEEK_10:
+		return DISCONNECT_TIME_TO_DATA;
+	case FORMAT_UNIT:
+	case SEARCH_HIGH:
+	case SEARCH_LOW:
+	case SEARCH_EQUAL:
+		return DISCONNECT_LONG;
+	default:
+		return DISCONNECT_NONE;
 	}
 }
 
 /*
  * Assumes instance->time_expires has been set in higher level code.
+ *
+ * Locks: Caller must hold io_request_lock
  */
 
 static int NCR5380_set_timer(struct Scsi_Host *instance)
 {
-	unsigned long flags;
 	struct Scsi_Host *tmp, **prev;
 
-	save_flags(flags);
-	cli();
 	if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) {
-		restore_flags(flags);
 		return -1;
 	}
-	for (prev = &expires_first, tmp = expires_first; tmp;
-		prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), 
-		tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer)
-		if (((struct NCR5380_hostdata *)instance->hostdata)->time_expires < 
-			((struct NCR5380_hostdata *)tmp->hostdata)->time_expires) 
+	for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer)
+		if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires)
 			break;
 
 	((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp;
 	*prev = instance;
-   
+
 	mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires);
-	restore_flags(flags);
 	return 0;
 }
 
-/* Doing something about unwanted reentrancy here might be useful */
-void NCR5380_timer_fn(unsigned long surplus_to_requirements)
+/**
+ *	NCR5380_timer_fn	-	handle polled timeouts
+ *	@unused: unused
+ *
+ *	Walk the list of controllers, find which controllers have exceeded
+ *	their expiry timeout and then schedule the processing co-routine to
+ *	do the real work.
+ *
+ *	Doing something about unwanted reentrancy here might be useful 
+ *
+ *	Locks: disables irqs, takes and frees io_request_lock
+ */
+ 
+void NCR5380_timer_fn(unsigned long unused)
 {
-	unsigned long flags;
 	struct Scsi_Host *instance;
-	save_flags(flags);
-	cli();
-	for (; expires_first &&
-		time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); )
-	{
+
+	spin_lock_irq(&io_request_lock);
+	
+	for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) {
 		instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer;
 		((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL;
 		((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0;
@@ -685,90 +626,91 @@
 	}
 
 	del_timer(&usleep_timer);
-	if (expires_first) 
-	{
-		usleep_timer.expires = ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires;
+	if (expires_first) {
+		usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires;
 		add_timer(&usleep_timer);
 	}
-	restore_flags(flags);
-
-	spin_lock_irqsave(&io_request_lock, flags);
 	run_main();
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irq(&io_request_lock);
 }
-#endif				/* def USLEEP */
 
+/**
+ *	NCR5380_all_init	-	global setup
+ *
+ *	Set up the global values and timers needed by the NCR5380 driver
+ */
+ 
 static inline void NCR5380_all_init(void)
 {
 	static int done = 0;
 	if (!done) {
-#if (NDEBUG & NDEBUG_INIT)
-		printk("scsi : NCR5380_all_init()\n");
-#endif
+		dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n"));
 		done = 1;
-#ifdef USLEEP
 		init_timer(&usleep_timer);
 		usleep_timer.function = NCR5380_timer_fn;
-#endif
 	}
 }
 
-#ifdef AUTOPROBE_IRQ
-/*
- * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible)
- * 
- * Purpose : autoprobe for the IRQ line used by the NCR5380.  
- *
- * Inputs : instance - pointer to this instance of the NCR5380 driver,
- *          possible - bitmask of permissible interrupts.
- *
- * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired.
- * 
- * XXX no effort is made to deal with spurious interrupts. 
- */
-
 
 static int probe_irq __initdata = 0;
 
+/**
+ *	probe_intr	-	helper for IRQ autoprobe
+ *	@irq: interrupt number
+ *	@dev_id: unused
+ *	@regs: unused
+ *
+ *	Set a flag to indicate the IRQ in question was received. This is
+ *	used by the IRQ probe code.
+ */
+ 
 static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	probe_irq = irq;
 }
 
+/**
+ *	NCR5380_probe_irq	-	find the IRQ of an NCR5380
+ *	@instance: NCR5380 controller
+ *	@possible: bitmask of ISA IRQ lines
+ *
+ *	Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
+ *	and then looking to see what interrupt actually turned up.
+ *
+ *	Locks: none, irqs must be enabled on entry
+ */
+
 static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
 {
 	NCR5380_local_declare();
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-	instance->hostdata;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	unsigned long timeout;
 	int trying_irqs, i, mask;
 	NCR5380_setup(instance);
 
 	for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
-		if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL)
-					  == 0))
+		if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0))
 			trying_irqs |= mask;
 
 	timeout = jiffies + (250 * HZ / 1000);
 	probe_irq = IRQ_NONE;
 
-/*
- * A interrupt is triggered whenever BSY = false, SEL = true
- * and a bit set in the SELECT_ENABLE_REG is asserted on the 
- * SCSI bus.
- *
- * Note that the bus is only driven when the phase control signals
- * (I/O, C/D, and MSG) match those in the TCR, so we must reset that
- * to zero.
- */
+	/*
+	 * A interrupt is triggered whenever BSY = false, SEL = true
+	 * and a bit set in the SELECT_ENABLE_REG is asserted on the 
+	 * SCSI bus.
+	 *
+	 * Note that the bus is only driven when the phase control signals
+	 * (I/O, C/D, and MSG) match those in the TCR, so we must reset that
+	 * to zero.
+	 */
 
 	NCR5380_write(TARGET_COMMAND_REG, 0);
 	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
-		      ICR_ASSERT_SEL);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);
 
-	while (probe_irq == IRQ_NONE && time_before(jiffies,timeout))
+	while (probe_irq == IRQ_NONE && time_before(jiffies, timeout))
 		barrier();
 
 	NCR5380_write(SELECT_ENABLE_REG, 0);
@@ -780,15 +722,16 @@
 
 	return probe_irq;
 }
-#endif				/* AUTOPROBE_IRQ */
 
-/*
- * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+/**
+ *	NCR58380_print_options	-	show options
+ *	@instance: unused for now
+ *
+ *	Called by probe code indicating the NCR5380 driver options that 
+ *	were selected. At some point this will switch to runtime options
+ *	read from the adapter in question
  *
- * Purpose : called by probe code indicating the NCR5380 driver
- *           options that were selected.
- *
- * Inputs : instance, pointer to this instance.  Unused.
+ *	Locks: none
  */
 
 static void __init NCR5380_print_options(struct Scsi_Host *instance)
@@ -815,29 +758,25 @@
 #ifdef PSEUDO_DMA
 	       " PSEUDO DMA"
 #endif
-#ifdef SCSI2
-	       " SCSI-2"
-#endif
 #ifdef UNSAFE
 	       " UNSAFE "
 #endif
 	    );
-#ifdef USLEEP
 	printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);
-#endif
 	printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
 	if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) {
 		printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);
 	}
 }
 
-/*
- * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+/**
+ *	NCR5380_print_status 	-	dump controller info
+ *	@instance: controller to dump
  *
- * Purpose : print commands in the various queues, called from
- *      NCR5380_abort and NCR5380_debug to aid debugging.
+ *	Print commands in the various queues, called from NCR5380_abort 
+ *	and NCR5380_debug to aid debugging.
  *
- * Inputs : instance, pointer to this instance.  
+ *	Locks: called functions disable irqs, missing queue lock in proc call
  */
 
 static void NCR5380_print_status(struct Scsi_Host *instance)
@@ -846,16 +785,12 @@
 	char *start;
 	int len;
 
-	printk("NCR5380 : coroutine is%s running.\n",
-	       main_running ? "" : "n't");
+	printk("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't");
 
-#ifdef NDEBUG
-	NCR5380_print(instance);
-	NCR5380_print_phase(instance);
-#endif
+	NCR5380_dprint(NDEBUG_ANY, instance);
+	NCR5380_dprint_phase(NDEBUG_ANY, instance);
 
-	len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr),
-				instance->host_no, 0);
+	len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0);
 	pr_bfr[len] = 0;
 	printk("\n%s\n", pr_bfr);
 }
@@ -886,18 +821,14 @@
 #ifndef NCR5380_proc_info
 static
 #endif
-int NCR5380_proc_info(
-			     char *buffer, char **start, off_t offset,
-			     int length, int hostno, int inout)
+int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
-	unsigned long flags;
 	char *pos = buffer;
 	struct Scsi_Host *instance;
 	struct NCR5380_hostdata *hostdata;
 	Scsi_Cmnd *ptr;
 
-	for (instance = first_instance; instance &&
-	     instance->host_no != hostno; instance = instance->next);
+	for (instance = first_instance; instance && instance->host_no != hostno; instance = instance->next);
 	if (!instance)
 		return (-ESRCH);
 	hostdata = (struct NCR5380_hostdata *) instance->hostdata;
@@ -935,32 +866,27 @@
 		SPRINTF("IRQ: %d.\n", instance->irq);
 
 #ifdef DTC_PUBLIC_RELEASE
-	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n",
-		dtc_wmaxi, dtc_maxi);
+	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n", dtc_wmaxi, dtc_maxi);
 #endif
 #ifdef PAS16_PUBLIC_RELEASE
-	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n",
-		pas_wmaxi, pas_maxi);
+	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n", pas_wmaxi, pas_maxi);
 #endif
-	save_flags(flags);
-	cli();
+	spin_lock_irq(&io_request_lock);
 	SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't");
 	if (!hostdata->connected)
 		SPRINTF("scsi%d: no currently connected command\n", instance->host_no);
 	else
-		pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected,
-				       pos, buffer, length);
+		pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length);
 	SPRINTF("scsi%d: issue_queue\n", instance->host_no);
-	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr;
-	     ptr = (Scsi_Cmnd *) ptr->host_scribble)
+	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
 		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
 
 	SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);
-	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
-	     ptr = (Scsi_Cmnd *) ptr->host_scribble)
+	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
 		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
 
-	restore_flags(flags);
+	spin_unlock_irq(&io_request_lock);
+	
 	*start = buffer;
 	if (pos - buffer < offset)
 		return 0;
@@ -972,16 +898,14 @@
 static
 char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length)
 {
-	SPRINTF("scsi%d : destination target %d, lun %d\n",
-		cmd->host->host_no, cmd->target, cmd->lun);
+	SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->host->host_no, cmd->target, cmd->lun);
 	SPRINTF("        command = ");
 	pos = lprint_command(cmd->cmnd, pos, buffer, length);
 	return (pos);
 }
 
 static
-char *lprint_command(unsigned char *command,
-		     char *pos, char *buffer, int length)
+char *lprint_command(unsigned char *command, char *pos, char *buffer, int length)
 {
 	int i, s;
 	pos = lprint_opcode(command[0], pos, buffer, length);
@@ -999,17 +923,18 @@
 }
 
 
-/* 
- * Function : void NCR5380_init (struct Scsi_Host *instance, flags)
+/**
+ *	NCR5380_init	-	initialise an NCR5380
+ *	@instance: adapter to configure
+ *	@flags: control flags
  *
- * Purpose : initializes *instance and corresponding 5380 chip,
+ *	Initializes *instance and corresponding 5380 chip,
  *      with flags OR'd into the initial flags value.
  *
- * Inputs : instance - instantiation of the 5380 driver.  
- *
- * Notes : I assume that the host, hostno, and id bits have been
+ *	Notes : I assume that the host, hostno, and id bits have been
  *      set correctly.  I don't care about the irq and other fields. 
- * 
+ *
+ *	Locks: interrupts must be enabled when we are called 
  */
 
 static void __init NCR5380_init(struct Scsi_Host *instance, int flags)
@@ -1017,9 +942,10 @@
 	NCR5380_local_declare();
 	int i, pass;
 	unsigned long timeout;
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-	instance->hostdata;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 
+	if(in_interrupt())
+		printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
 	/* 
 	 * On NCR53C400 boards, NCR5380 registers are mapped 8 past 
 	 * the base address.
@@ -1031,7 +957,6 @@
 #endif
 
 	NCR5380_setup(instance);
-
 	NCR5380_all_init();
 
 	hostdata->aborted = 0;
@@ -1070,17 +995,13 @@
 		the_template = instance->hostt;
 		first_instance = instance;
 	}
-#ifdef USLEEP
 	hostdata->time_expires = 0;
 	hostdata->next_timer = NULL;
-#endif
 
 #ifndef AUTOSENSE
 	if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)
-		)
-		    printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n"
-			   "         without AUTOSENSE option, contingent allegiance conditions may\n"
-		"         be incorrectly cleared.\n", instance->host_no);
+		    printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" "         without AUTOSENSE option, contingent allegiance conditions may\n"
+		    	   "         be incorrectly cleared.\n", instance->host_no);
 #endif				/* def AUTOSENSE */
 
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1106,50 +1027,40 @@
 	 * failing, do a hard reset of the SCSI bus 
 	 */
 
-	for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) &&
-	     pass <= 6; ++pass) {
+	for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
 		switch (pass) {
 		case 1:
 		case 3:
 		case 5:
-			printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
-			       instance->host_no);
+			printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
 			timeout = jiffies + 5 * HZ;
-			while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY));
+			while (time_before(jiffies, timeout) && (NCR5380_read(STATUS_REG) & SR_BSY));
 			break;
 		case 2:
-			printk("scsi%d: bus busy, attempting abort\n",
-			       instance->host_no);
+			printk("scsi%d: bus busy, attempting abort\n", instance->host_no);
 			do_abort(instance);
 			break;
 		case 4:
-			printk("scsi%d: bus busy, attempting reset\n",
-			       instance->host_no);
+			printk("scsi%d: bus busy, attempting reset\n", instance->host_no);
 			do_reset(instance);
 			break;
 		case 6:
-			printk("scsi%d: bus locked solid or invalid override\n",
-			       instance->host_no);
+			printk("scsi%d: bus locked solid or invalid override\n", instance->host_no);
 		}
 	}
 }
 
-/* 
- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
- *      void (*done)(Scsi_Cmnd *)) 
- *
- * Purpose :  enqueues a SCSI command
+/**
+ *	NCR5380_queue_command 		-	queue a command
+ *	@cmd: SCSI command
+ *	@done: completion handler
  *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- *      a pointer to the command descriptor.
- * 
- * Returns : 0
- *
- * Side effects : 
  *      cmd is added to the per instance issue_queue, with minor 
  *      twiddling done to the host specific fields of cmd.  If the 
  *      main coroutine is not running, it is restarted.
  *
+ *	Locks: io_request lock held by caller. Called functions drop and
+ *	retake this lock. Called functions take dma lock.
  */
 
 /* Only make static if a wrapper function is used */
@@ -1158,16 +1069,14 @@
 #endif
 int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) {
 	struct Scsi_Host *instance = cmd->host;
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-	 instance->hostdata;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	Scsi_Cmnd *tmp;
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
 	switch (cmd->cmnd[0]) {
-		case WRITE_6:
-		    case WRITE_10:
-		    printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
-			   instance->host_no);
+	case WRITE_6:
+	case WRITE_10:
+		printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no);
 		cmd->result = (DID_ERROR << 16);
 		done(cmd);
 		return 0;
@@ -1175,31 +1084,22 @@
 #endif				/* (NDEBUG & NDEBUG_NO_WRITE) */
 
 #ifdef NCR5380_STATS
-#if 0
-	if (!hostdata->connected && !hostdata->issue_queue &&
-	    !hostdata->disconnected_queue) {
-		hostdata->timebase = jiffies;
-	}
-#endif
-#ifdef NCR5380_STAT_LIMIT
-	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
-#endif
-		switch (cmd->cmnd[0]) {
-			case WRITE:
-			    case WRITE_6:
-			    case WRITE_10:
-			    hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+	switch (cmd->cmnd[0]) {
+		case WRITE:
+		case WRITE_6:
+		case WRITE_10:
+			hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
 			hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
 			hostdata->pendingw++;
 			break;
-			case READ:
-			    case READ_6:
-			    case READ_10:
-			    hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+		case READ:
+		case READ_6:
+		case READ_10:
+			hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
 			hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
 			hostdata->pendingr++;
 			break;
-		}
+	}
 #endif
 
 	/* 
@@ -1209,10 +1109,8 @@
 
 	cmd->host_scribble = NULL;
 	cmd->scsi_done = done;
-
 	cmd->result = 0;
 
-
 	/* 
 	 * Insert the cmd into the issue queue. Note that REQUEST SENSE 
 	 * commands are added to the head of the queue since any command will
@@ -1225,31 +1123,28 @@
 		cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
 		hostdata->issue_queue = cmd;
 	} else {
-		for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble;
-		     tmp = (Scsi_Cmnd *) tmp->host_scribble);
+		for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
 		LIST(cmd, tmp);
 		tmp->host_scribble = (unsigned char *) cmd;
 	}
-#if (NDEBUG & NDEBUG_QUEUES)
-	printk("scsi%d : command added to %s of queue\n", instance->host_no,
-	       (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-#endif
+	dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"));
 
-/* Run the coroutine if it isn't already running. */
+	/* Run the coroutine if it isn't already running. */
 	run_main();
 	return 0;
 }
 
-/*
- * Function : NCR5380_main (void) 
+/**
+ *	NCR5380_main	-	NCR state machines
  *
- * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
+ *	NCR5380_main is a coroutine that runs as long as more work can 
  *      be done on the NCR5380 host adapters in a system.  Both 
  *      NCR5380_queue_command() and NCR5380_intr() will try to start it 
  *      in case it is not running.
  * 
- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
- *  reenable them.  This prevents reentrancy and kernel stack overflow.
+ *	Locks; The caller must hold the io_request_lock. The lock will still be
+ *	held on return but may be dropped while running. Called functions take
+ *	the DMA lock.
  */
 
 static void NCR5380_main(void) {
@@ -1257,7 +1152,6 @@
 	struct Scsi_Host *instance;
 	struct NCR5380_hostdata *hostdata;
 	int done;
-	unsigned long flags;
 
 	/*
 	 * We run (with interrupts disabled) until we're sure that none of 
@@ -1271,43 +1165,22 @@
 	 * this should prevent any race conditions.
 	 */
 
-	spin_unlock_irq(&io_request_lock);
-	
-	save_flags(flags);
-	
 	do {
-		cli();		/* Freeze request queues */
+		/* Lock held here */
 		done = 1;
-		for (instance = first_instance; instance &&
-		     instance->hostt == the_template; instance = instance->next) {
-			 hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-			 cli();
-#ifdef USLEEP
+		for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) {
+			hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+			/* Lock held here */
 			if (!hostdata->connected && !hostdata->selecting) {
-#else
-			if (!hostdata->connected) {
-#endif			
-#if (NDEBUG & NDEBUG_MAIN)
-				printk("scsi%d : not connected\n", instance->host_no);
-#endif
+				dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no));
 				/*
 				 * Search through the issue_queue for a command destined
 				 * for a target that's not busy.
 				 */
-#if (NDEBUG & NDEBUG_LISTS)
-				for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble);
-				/*printk("%p  ", tmp); */
-				if ((tmp == prev) && tmp)
-					printk(" LOOP\n");	/* else printk("\n"); */
-#endif
-				for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
-				     prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
-				     tmp->host_scribble) {
-
-#if (NDEBUG & NDEBUG_LISTS)
+				for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) 
+				{
 					if (prev != tmp)
-						printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun);
-#endif
+						dprintk(NDEBUG_LISTS, ("MAIN tmp=%p   target=%d   busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun));
 					/*  When we find one, remove it from the issue queue. */
 					if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) {
 						if (prev) {
@@ -1319,8 +1192,6 @@
 						}
 						tmp->host_scribble = NULL;
 
-						/* reenable interrupts after finding one */
-						restore_flags(flags);
 
 						/* 
 						 * Attempt to establish an I_T_L nexus here. 
@@ -1328,10 +1199,7 @@
 						 * On failure, we must add the command back to the
 						 *   issue queue so we can keep trying. 
 						 */
-#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
-						printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n",
-						       instance->host_no, tmp->target, tmp->lun);
-#endif
+						dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun));
 
 						/*
 						 * A successful selection is defined as one that 
@@ -1343,105 +1211,81 @@
 						 * and see if we can do an information transfer,
 						 * with failures we will restart.
 						 */
-#ifdef USLEEP
-						hostdata->selecting = 0; /* RvC: have to preset this
-							to indicate a new command is being performed */
-#endif
+						hostdata->selecting = 0;	
+						/* RvC: have to preset this to indicate a new command is being performed */
 
 						if (!NCR5380_select(instance, tmp,
-						/* 
-						 * REQUEST SENSE commands are issued without tagged
-						 * queueing, even on SCSI-II devices because the 
-						 * contingent allegiance condition exists for the 
-						 * entire unit.
-						 */
-								    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
-							     TAG_NEXT)) {
+								    /* 
+								     * REQUEST SENSE commands are issued without tagged
+								     * queueing, even on SCSI-II devices because the 
+								     * contingent allegiance condition exists for the 
+								     * entire unit.
+								     */
+								    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
 							break;
 						} else {
-							cli();
 							LIST(tmp, hostdata->issue_queue);
-							tmp->host_scribble = (unsigned char *)
-							    hostdata->issue_queue;
+							tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
 							hostdata->issue_queue = tmp;
 							done = 0;
-							restore_flags(flags);
-#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
-							printk("scsi%d : main(): select() failed, returned to issue_queue\n",
-							       instance->host_no);
-#endif
+							dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no));
 						}
+						/* lock held here still */
 					}	/* if target/lun is not busy */
 				}	/* for */
+				/* exited locked */
 			}	/* if (!hostdata->connected) */
-#ifdef USLEEP
-			if (hostdata->selecting) 
-			{
-				tmp = (Scsi_Cmnd *)hostdata->selecting;
-				if (!NCR5380_select(instance, tmp, 
-					(tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) 
-				{
+			if (hostdata->selecting) {
+				tmp = (Scsi_Cmnd *) hostdata->selecting;
+				/* Selection will drop and retake the lock */
+				if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
 					/* Ok ?? */
-				}
-				else
-				{
+				} else {
 					/* RvC: device failed, so we wait a long time
-					this is needed for Mustek scanners, that
-					do not respond to commands immediately
-					after a scan */
-					printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n",
-						instance->host_no, tmp->target);
-					cli();
+					   this is needed for Mustek scanners, that
+					   do not respond to commands immediately
+					   after a scan */
+					printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target);
+					//spin_lock_irq(&io_request_lock);
 					LIST(tmp, hostdata->issue_queue);
 					tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
 					hostdata->issue_queue = tmp;
-					restore_flags(flags);
+					//spin_unlock_irq(&io_request_lock);
 
 					hostdata->time_expires = jiffies + USLEEP_WAITLONG;
-					NCR5380_set_timer (instance);
+					NCR5380_set_timer(instance);
 				}
-			} /* if hostdata->selecting */
-#endif
+			}	/* if hostdata->selecting */
 			if (hostdata->connected
 #ifdef REAL_DMA
 			    && !hostdata->dmalen
 #endif
-#ifdef USLEEP
 			    && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
-#endif
 			    ) {
-				restore_flags(flags);
-#if (NDEBUG & NDEBUG_MAIN)
-				printk("scsi%d : main() : performing information transfer\n",
-				       instance->host_no);
-#endif
+				dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no));
 				NCR5380_information_transfer(instance);
-#if (NDEBUG & NDEBUG_MAIN)
-				printk("scsi%d : main() : done set false\n", instance->host_no);
-#endif
+				dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no));
 				done = 0;
 			} else
 				break;
 		}		/* for instance */
 	} while (!done);
-	spin_lock_irq(&io_request_lock);
-  /* 	cli();*/
-	main_running = 0;
+	/* Exit lock held */
+	clear_bit(0, &main_running);
 }
 
 #ifndef DONT_USE_INTR
 #include <linux/blk.h>
 #include <linux/spinlock.h>
 
-/*
- * Function : void NCR5380_intr (int irq)
- * 
- * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+/**
+ * 	NCR5380_intr	-	generic NCR5380 irq handler
+ *
+ *	Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
  *      from the disconnected queue, and restarting NCR5380_main() 
  *      as required.
  *
- * Inputs : int irq, irq that caused this interrupt.
- *
+ *	Locks: caller must hold the io_request lock.
  */
 
 static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) {
@@ -1449,17 +1293,12 @@
 	struct Scsi_Host *instance;
 	int done;
 	unsigned char basr;
-	unsigned long flags;
 
-	 save_flags(flags);
-	 cli();
-#if (NDEBUG & NDEBUG_INTR)
-	 printk("scsi : NCR5380 irq %d triggered\n", irq);
-#endif
+	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq));
+
 	do {
 		done = 1;
-		for (instance = first_instance; instance && (instance->hostt ==
-				the_template); instance = instance->next)
+		for (instance = first_instance; instance && (instance->hostt == the_template); instance = instance->next)
 			if (instance->irq == irq) {
 
 				/* Look for pending interrupts */
@@ -1467,34 +1306,19 @@
 				basr = NCR5380_read(BUS_AND_STATUS_REG);
 				/* XXX dispatch to appropriate routine if found and done=0 */
 				if (basr & BASR_IRQ) {
-#if (NDEBUG & NDEBUG_INTR)
-					NCR5380_print(instance);
-#endif
-					if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
-					    (SR_SEL | SR_IO)) {
+					NCR5380_dprint(NDEBUG_INTR, instance);
+					if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
 						done = 0;
-						restore_flags(flags);
-#if (NDEBUG & NDEBUG_INTR)
-						printk("scsi%d : SEL interrupt\n", instance->host_no);
-#endif
+						dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no));
 						NCR5380_reselect(instance);
 						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 					} else if (basr & BASR_PARITY_ERROR) {
-#if (NDEBUG & NDEBUG_INTR)
-						printk("scsi%d : PARITY interrupt\n", instance->host_no);
-#endif
+						dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no));
 						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 					} else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
-#if (NDEBUG & NDEBUG_INTR)
-						printk("scsi%d : RESET interrupt\n", instance->host_no);
-#endif
+						dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no));
 						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 					} else {
-/*  
- * XXX the rest of the interrupt conditions should *only* occur during a 
- * DMA transfer, which I haven't gotten around to fixing yet.
- */
-
 #if defined(REAL_DMA)
 						/*
 						 * We should only get PHASE MISMATCH and EOP interrupts
@@ -1502,14 +1326,11 @@
 						 * the current setting of the MODE register.
 						 */
 
-						if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr &
-						BASR_END_DMA_TRANSFER) ||
-											  !(basr & BASR_PHASE_MATCH))) {
+						if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) {
 							int transfered;
 
 							if (!hostdata->connected)
-								panic("scsi%d : received end of DMA interrupt with no connected cmd\n",
-								      instance->hostno);
+								panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno);
 
 							transfered = (hostdata->dmalen - NCR5380_dma_residual(instance));
 							hostdata->connected->SCp.this_residual -= transferred;
@@ -1522,15 +1343,13 @@
 								unsigned long timeout = jiffies + NCR_TIMEOUT;
 
 								spin_unlock_irq(&io_request_lock);
-								while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK
-								       && time_before(jiffies, timeout));
+								while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && time_before(jiffies, timeout));
 								spin_lock_irq(&io_request_lock);
-								
-								if (time_after_eq(jiffies, timeout) )
-									printk("scsi%d: timeout at NCR5380.c:%d\n",
-									       host->host_no, __LINE__);
+
+								if (time_after_eq(jiffies, timeout))
+									printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__);
 							}
-#else				/* NCR_TIMEOUT */
+#else /* NCR_TIMEOUT */
 							while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
 #endif
 
@@ -1538,9 +1357,7 @@
 							NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 						}
 #else
-#if (NDEBUG & NDEBUG_INTR)
-						printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
-#endif
+						dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)));
 						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 #endif
 					}
@@ -1551,6 +1368,17 @@
 	} while (!done);
 }
 
+/**
+ *	do_NCR5380_intr
+ *	@irq: interrupt number
+ *	@dev_id: device info
+ *	@regs: registers (unused)
+ *
+ *	Takes the io_request_lock and invokes the generic NCR5380 interrupt
+ *	handler code
+ *
+ *	Locks: takes and releases the io_request lock
+ */
 
 static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) {
 	unsigned long flags;
@@ -1559,32 +1387,38 @@
 	 NCR5380_intr(irq, dev_id, regs);
 	 spin_unlock_irqrestore(&io_request_lock, flags);
 }
-
 #endif
 
+
+/**
+ *	collect_stats		-	collect stats on a scsi command
+ *	@hostdata: adapter 
+ *	@cmd: command being issued
+ *
+ *	Update the statistical data by parsing the command in question
+ */
+ 
+static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) 
+{
 #ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) {
-#ifdef NCR5380_STAT_LIMIT
-	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
-#endif
-		switch (cmd->cmnd[0]) {
-			case WRITE:
-			    case WRITE_6:
-			    case WRITE_10:
-			    hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
-			/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */
-			hostdata->pendingw--;
-			break;
-			case READ:
-			case READ_6:
-			case READ_10:
-			hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
-			/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */
-			hostdata->pendingr--;
-			break;
-		}
-}
+	switch (cmd->cmnd[0]) {
+	case WRITE:
+	case WRITE_6:
+	case WRITE_10:
+		hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+		hostdata->pendingw--;
+		break;
+	case READ:
+	case READ_6:
+	case READ_10:
+		hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+		hostdata->pendingr--;
+		break;
+	}
 #endif
+}
+
+
 /* 
  * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
  *      int tag);
@@ -1614,55 +1448,44 @@
  *
  *      If failed (no target) : cmd->scsi_done() will be called, and the 
  *              cmd->result host byte set to DID_BAD_TARGET.
+ *
+ *	Locks: caller holds io_request_lock
  */
-static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) {
+ 
+static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) 
+{
 	NCR5380_local_declare();
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	unsigned char tmp[3], phase;
 	unsigned char *data;
 	int len;
 	unsigned long timeout;
-	unsigned long flags;
-#ifdef USLEEP
 	unsigned char value;
-#endif
-
 	NCR5380_setup(instance);
 
-#ifdef USLEEP
-
-	if (hostdata->selecting) 
-	{
+	if (hostdata->selecting) {
 		goto part2;	/* RvC: sorry prof. Dijkstra, but it keeps the
 				   rest of the code nearly the same */
 	}
-#endif
 
-	 hostdata->restart_select = 0;
-#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION)
-	 NCR5380_print(instance);
-	 printk("scsi%d : starting arbitration, id = %d\n", instance->host_no,
-		instance->this_id);
-#endif
-	 save_flags(flags);
-	 cli();
+	hostdata->restart_select = 0;
+
+	NCR5380_dprint(NDEBUG_ARBITRATION, instance);
+	dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id));
 
 	/* 
 	 * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
 	 * data bus during SELECTION.
 	 */
 
-	 NCR5380_write(TARGET_COMMAND_REG, 0);
-
+	NCR5380_write(TARGET_COMMAND_REG, 0);
 
 	/* 
 	 * Start arbitration.
 	 */
 
-	 NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
-	 NCR5380_write(MODE_REG, MR_ARBITRATE);
-
-	 restore_flags(flags);
+	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+	NCR5380_write(MODE_REG, MR_ARBITRATE);
 
 	/* Wait for arbitration logic to complete */
 #if NCR_TIMEOUT
@@ -1672,11 +1495,11 @@
 		spin_unlock_irq(&io_request_lock);
 
 		while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
-		       && time_before(jiffies,timeout));
+		       && time_before(jiffies, timeout));
 
 		spin_lock_irq(&io_request_lock);
-		       
-		if (time_after_eq(jiffies,timeout)) {
+
+		if (time_after_eq(jiffies, timeout)) {
 			printk("scsi: arbitration timeout at %d\n", __LINE__);
 			NCR5380_write(MODE_REG, MR_BASE);
 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -1687,11 +1510,7 @@
 	while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));
 #endif
 
-#if (NDEBUG & NDEBUG_ARBITRATION)
-	 printk("scsi%d : arbitration complete\n", instance->host_no);
-/* Avoid GCC 2.4.5 asm needs to many reloads error */
-	 __asm__("nop");
-#endif
+	dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no));
 
 	/* 
 	 * The arbitration delay is 2.2us, but this is a minimum and there is 
@@ -1700,34 +1519,25 @@
 	 *
 	 */
 
-	 udelay(3);
+	udelay(3);
 
 	/* Check for lost arbitration */
-	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
-	     (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
-	  (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
+	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
 		NCR5380_write(MODE_REG, MR_BASE);
-#if (NDEBUG & NDEBUG_ARBITRATION)
-		printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n",
-		       instance->host_no);
-#endif
+		dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no));
 		return -1;
 	}
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
 
 	if (!(hostdata->flags & FLAG_DTC3181E) &&
-		/* RvC: DTC3181E has some trouble with this
-		 *	so we simply removed it. Seems to work with
-		 *	only Mustek scanner attached
-		 */
-		(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) 
-	{
+	    /* RvC: DTC3181E has some trouble with this
+	     *      so we simply removed it. Seems to work with
+	     *      only Mustek scanner attached
+	     */
+	    (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
 		NCR5380_write(MODE_REG, MR_BASE);
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-#if (NDEBUG & NDEBUG_ARBITRATION)
-		printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n",
-		       instance->host_no);
-#endif
+		dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no));
 		return -1;
 	}
 	/* 
@@ -1737,10 +1547,7 @@
 
 	udelay(2);
 
-#if (NDEBUG & NDEBUG_ARBITRATION)
-	printk("scsi%d : won arbitration\n", instance->host_no);
-#endif
-
+	dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no));
 
 	/* 
 	 * Now that we have won arbitration, start Selection process, asserting 
@@ -1755,8 +1562,7 @@
 	 * phase immediately after selection.
 	 */
 
-	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
-		     ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
 	NCR5380_write(MODE_REG, MR_BASE);
 
 	/* 
@@ -1772,8 +1578,7 @@
 	udelay(1);		/* wingel -- wait two bus deskew delay >2*45ns */
 
 	/* Reset BSY */
-	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
-				       ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
 
 	/* 
 	 * Something weird happens when we cease to drive BSY - looks
@@ -1794,9 +1599,7 @@
 
 	udelay(1);
 
-#if (NDEBUG & NDEBUG_SELECTION)
-	printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target);
-#endif
+	dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, cmd->target));
 
 	/* 
 	 * The SCSI specification calls for a 250 ms timeout for the actual 
@@ -1811,40 +1614,30 @@
 	 * and it's detecting as true.  Sigh.
 	 */
 
-#ifdef USLEEP
-	hostdata->select_time = 0; /* we count the clock ticks at which we polled */
+	hostdata->select_time = 0;	/* we count the clock ticks at which we polled */
 	hostdata->selecting = cmd;
 
 part2:
-    	/* RvC: here we enter after a sleeping period, or immediately after
-		execution of part 1
-		we poll only once ech clock tick */
+	/* RvC: here we enter after a sleeping period, or immediately after
+	   execution of part 1
+	   we poll only once ech clock tick */
 	value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
 
-	if (!value && (hostdata->select_time < 25)) 
-	{
+	if (!value && (hostdata->select_time < 25)) {
 		/* RvC: we still must wait for a device response */
-		hostdata->select_time++; /* after 25 ticks the device has failed */
+		hostdata->select_time++;	/* after 25 ticks the device has failed */
 		hostdata->time_expires = jiffies + 1;
 		NCR5380_set_timer(instance);
 		return 0;	/* RvC: we return here with hostdata->selecting set,
 				   to go to sleep */
 	}
 
-	hostdata->selecting = 0; /* clear this pointer, because we passed the
-				waiting period */
-#else
-	spin_unlock_irq(&io_request_lock);
-	while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
-					(SR_BSY | SR_IO)));
-	spin_lock_irq(&io_request_lock);
-#endif
-	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
-	    (SR_SEL | SR_IO)) {
+	hostdata->selecting = 0;	/* clear this pointer, because we passed the
+					   waiting period */
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		NCR5380_reselect(instance);
-		printk("scsi%d : reselection after won arbitration?\n",
-		       instance->host_no);
+		printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
 		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		return -1;
 	}
@@ -1864,22 +1657,15 @@
 			printk("scsi%d : weirdness\n", instance->host_no);
 			if (hostdata->restart_select)
 				printk("\trestart select\n");
-#if (NDEBUG & NDEBUG_SELECTION)
-			NCR5380_print(instance);
-#endif
+			NCR5380_dprint(NDEBUG_SELECTION, instance);
 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 			return -1;
 		}
 		cmd->result = DID_BAD_TARGET << 16;
-#ifdef NCR5380_STATS
 		collect_stats(hostdata, cmd);
-#endif
 		cmd->scsi_done(cmd);
 		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-#if (NDEBUG & NDEBUG_SELECTION)
-		printk("scsi%d : target did not respond within 250ms\n",
-		       instance->host_no);
-#endif
+		dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no));
 		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		return 0;
 	}
@@ -1908,7 +1694,7 @@
 		spin_unlock_irq(&io_request_lock);
 		while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout));
 		spin_lock_irq(&io_request_lock);
-		
+
 		if (time_after_eq(jiffies, timeout)) {
 			printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -1919,47 +1705,20 @@
 	while (!(NCR5380_read(STATUS_REG) & SR_REQ));
 #endif				/* def NCR_TIMEOUT */
 
-#if (NDEBUG & NDEBUG_SELECTION)
-	printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n",
-	       instance->host_no, cmd->target);
-#endif
+	dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target));
 	tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun);
-#ifdef SCSI2
-	if (cmd->device->tagged_queue && (tag != TAG_NONE)) {
-		tmp[1] = SIMPLE_QUEUE_TAG;
-		if (tag == TAG_NEXT) {
-			/* 0 is TAG_NONE, used to imply no tag for this command */
-			if (cmd->device->current_tag == 0)
-				cmd->device->current_tag = 1;
-
-			cmd->tag = cmd->device->current_tag;
-			cmd->device->current_tag++;
-		} else
-			cmd->tag = (unsigned char) tag;
-
-		tmp[2] = cmd->tag;
-		hostdata->last_message = SIMPLE_QUEUE_TAG;
-		len = 3;
-	} else
-#endif				/* def SCSI2 */
-	{
-		len = 1;
-		cmd->tag = 0;
-	}
+
+	len = 1;
+	cmd->tag = 0;
 
 	/* Send message(s) */
 	data = tmp;
 	phase = PHASE_MSGOUT;
 	NCR5380_transfer_pio(instance, &phase, &len, &data);
-#if (NDEBUG & NDEBUG_SELECTION)
-	printk("scsi%d : nexus established.\n", instance->host_no);
-#endif
+	dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no));
 	/* XXX need to handle errors here */
 	hostdata->connected = cmd;
-#ifdef SCSI2
-	if (!cmd->device->tagged_queue)
-#endif
-		hostdata->busy[cmd->target] |= (1 << cmd->lun);
+	hostdata->busy[cmd->target] |= (1 << cmd->lun);
 
 	initialize_SCp(cmd);
 
@@ -1992,27 +1751,22 @@
  * counts, we will always do a pseudo DMA or DMA transfer.
  */
 
-static int NCR5380_transfer_pio(struct Scsi_Host *instance,
-		unsigned char *phase, int *count, unsigned char **data) {
+static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
 	NCR5380_local_declare();
-	register unsigned char p = *phase, tmp;
-	register int c = *count;
-	register unsigned char *d = *data;
-#ifdef USLEEP
+	unsigned char p = *phase, tmp;
+	int c = *count;
+	unsigned char *d = *data;
 	/*
-	 *	RvC: some administrative data to process polling time
+	 *      RvC: some administrative data to process polling time
 	 */
 	int break_allowed = 0;
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-#endif
 	NCR5380_setup(instance);
 
-#if (NDEBUG & NDEBUG_PIO)
 	if (!(p & SR_IO))
-		 printk("scsi%d : pio write %d bytes\n", instance->host_no, c);
+		dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c));
 	else
-		 printk("scsi%d : pio read %d bytes\n", instance->host_no, c);
-#endif
+		dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c));
 
 	/* 
 	 * The NCR5380 chip will only drive the SCSI bus when the 
@@ -2022,56 +1776,42 @@
 
 	 NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
-#ifdef USLEEP
 	/* RvC: don't know if this is necessary, but other SCSI I/O is short
-	 *	so breaks are not necessary there
+	 *      so breaks are not necessary there
 	 */
-	if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) 
-	{
+	if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) {
 		break_allowed = 1;
 	}
-#endif
-
-
 	do {
 		/* 
 		 * Wait for assertion of REQ, after which the phase bits will be 
 		 * valid 
 		 */
 
-#ifdef USLEEP
 		/* RvC: we simply poll once, after that we stop temporarily
-		 *	and let the device buffer fill up
-		 *	if breaking is not allowed, we keep polling as long as needed
+		 *      and let the device buffer fill up
+		 *      if breaking is not allowed, we keep polling as long as needed
 		 */
 
-		while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) &&
-			!break_allowed );
-		if (!(tmp & SR_REQ)) 
-		{
+		while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed);
+		if (!(tmp & SR_REQ)) {
 			/* timeout condition */
 			hostdata->time_expires = jiffies + USLEEP_SLEEP;
-			NCR5380_set_timer (instance);
+			NCR5380_set_timer(instance);
 			break;
 		}
-#else
-		while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) ); 
-#endif
 
-#if (NDEBUG & NDEBUG_HANDSHAKE)
-		printk("scsi%d : REQ detected\n", instance->host_no);
-#endif
+		dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no));
 
 		/* Check for phase mismatch */
 		if ((tmp & PHASE_MASK) != p) {
-#if (NDEBUG & NDEBUG_PIO)
-			printk("scsi%d : phase mismatch\n", instance->host_no);
-			NCR5380_print_phase(instance);
-#endif
+			dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no));
+			NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance);
 			break;
 		}
-		/* Do actual transfer from SCSI bus to / from memory */ if (!(p & SR_IO))
-			 NCR5380_write(OUTPUT_DATA_REG, *d);
+		/* Do actual transfer from SCSI bus to / from memory */
+		if (!(p & SR_IO))
+			NCR5380_write(OUTPUT_DATA_REG, *d);
 		else
 			*d = NCR5380_read(CURRENT_SCSI_DATA_REG);
 
@@ -2086,34 +1826,22 @@
 
 		if (!(p & SR_IO)) {
 			if (!((p & SR_MSG) && c > 1)) {
-				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-					      ICR_ASSERT_DATA);
-#if (NDEBUG & NDEBUG_PIO)
-				NCR5380_print(instance);
-#endif
-				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-				       ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+				NCR5380_dprint(NDEBUG_PIO, instance);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK);
 			} else {
-				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-				       ICR_ASSERT_DATA | ICR_ASSERT_ATN);
-#if (NDEBUG & NDEBUG_PIO)
-				NCR5380_print(instance);
-#endif
-				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-					      ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+				NCR5380_dprint(NDEBUG_PIO, instance);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
 			}
 		} else {
-#if (NDEBUG & NDEBUG_PIO)
-			NCR5380_print(instance);
-#endif
+			NCR5380_dprint(NDEBUG_PIO, instance);
 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
 		}
 
 		while (NCR5380_read(STATUS_REG) & SR_REQ);
 
-#if (NDEBUG & NDEBUG_HANDSHAKE)
-		printk("scsi%d : req false, handshake complete\n", instance->host_no);
-#endif
+		dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no));
 
 /*
  * We have several special cases to consider during REQ/ACK handshaking : 
@@ -2134,9 +1862,7 @@
 		}
 	} while (--c);
 
-#if (NDEBUG & NDEBUG_PIO)
-	printk("scsi%d : residual %d\n", instance->host_no, c);
-#endif
+	dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c));
 
 	*count = c;
 	*data = d;
@@ -2152,36 +1878,46 @@
 		return -1;
 }
 
+/**
+ *	do_reset	-	issue a reset command
+ *	@host: adapter to reset
+ *
+ *	Issue a reset sequence to the NCR5380 and try and get the bus
+ *	back into sane shape.
+ *
+ *	Locks: caller holds io_request lock
+ */
+ 
 static void do_reset(struct Scsi_Host *host) {
-	unsigned long flags;
-	 NCR5380_local_declare();
-	 NCR5380_setup(host);
+	NCR5380_local_declare();
+	NCR5380_setup(host);
+
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+	udelay(25);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ *      called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ *
+ * Locks: io_request lock held by caller
+ */
 
-	 save_flags(flags);
-	 cli();
-	 NCR5380_write(TARGET_COMMAND_REG,
-		 PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
-	 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
-	 udelay(25);
-	 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	 restore_flags(flags);
-}				/*
-
-				 * Function : do_abort (Scsi_Host *host)
-				 * 
-				 * Purpose : abort the currently established nexus.  Should only be 
-				 *      called from a routine which can drop into a 
-				 * 
-				 * Returns : 0 on success, -1 on failure.
-				 */ static int do_abort(struct Scsi_Host *host) {
+static int do_abort(struct Scsi_Host *host) {
 	NCR5380_local_declare();
 	unsigned char tmp, *msgptr, phase;
 	int len;
-	 NCR5380_setup(host);
+	NCR5380_setup(host);
 
 
 	/* Request message out phase */
-	 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 
 	/* 
 	 * Wait for the target to indicate a valid phase by asserting 
@@ -2195,11 +1931,10 @@
 
 	while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
 
-	 NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
 	if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
-			      ICR_ASSERT_ACK);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
 		while (NCR5380_read(STATUS_REG) & SR_REQ);
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 	}
@@ -2235,54 +1970,46 @@
  *
  *      Also, *phase, *count, *data are modified in place.
  *
+ *	Locks: io_request lock held by caller
  */
 
 
-static int NCR5380_transfer_dma(struct Scsi_Host *instance,
-		unsigned char *phase, int *count, unsigned char **data) {
+static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
 	NCR5380_local_declare();
 	register int c = *count;
 	register unsigned char p = *phase;
 	register unsigned char *d = *data;
 	unsigned char tmp;
-#if defined(PSEUDO_DMA) && !defined(UNSAFE)
-	unsigned long flags;
-#endif
 	int foo;
 #if defined(REAL_DMA_POLL)
 	int cnt, toPIO;
 	unsigned char saved_data = 0, overrun = 0, residue;
 #endif
 
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-	 instance->hostdata;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 
-	 NCR5380_setup(instance);
+	NCR5380_setup(instance);
 
 	if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
 		*phase = tmp;
 		return -1;
 	}
 #if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-#ifdef READ_OVERRUNS 
-	if (p & SR_IO) { c -= 2; }
-#endif
-#if (NDEBUG & NDEBUG_DMA)
-printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n",
-       instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" :
-       "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
+#ifdef READ_OVERRUNS
+	if (p & SR_IO) {
+		c -= 2;
+	}
 #endif
-hostdata->dma_len = (p & SR_IO) ?
-NCR5380_dma_read_setup(instance, d, c) :
-NCR5380_dma_write_setup(instance, d, c);
+	dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d));
+	hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);
 #endif
 
-NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
 #ifdef REAL_DMA
-NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
 #elif defined(REAL_DMA_POLL)
-NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
 #else
 	/*
 	 * Note : on my sample board, watch-dog timeouts occurred when interrupts
@@ -2290,58 +2017,38 @@
 	 * before the setting of DMA mode to after transfer of the last byte.
 	 */
 
-#if defined(PSEUDO_DMA) && !defined(UNSAFE)
-save_flags(flags);
-cli();
+#if defined(PSEUDO_DMA) && defined(UNSAFE)
+	spin_unlock_irq(&io_request_lock);
 #endif
 	/* KLL May need eop and parity in 53c400 */
-if (hostdata->flags & FLAG_NCR53C400)
-	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK
-		  | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE
-		      | MR_MONITOR_BSY);
-else
-	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+	if (hostdata->flags & FLAG_NCR53C400)
+		NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY);
+	else
+		NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
 #endif				/* def REAL_DMA */
 
-#if (NDEBUG & NDEBUG_DMA) & 0
-printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
-#endif
+	dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)));
 
-/* 
- * FOO stuff. For some UNAPPARENT reason, I'm getting 
- * watchdog timers fired on bootup for NO APPARENT REASON, meaning it's
- * probably a timing problem.
- *
- * Since this is the only place I have back-to-back writes, perhaps this 
- * is the problem?
- */
+	/* 
+	 *	On the PAS16 at least I/O recovery delays are not needed here.
+	 *	Everyone else seems to want them.
+	 */
 
-if (p & SR_IO)
-{
-#ifndef FOO
-udelay(1);
-#endif
-NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
-} else {
-#ifndef FOO
-	udelay(1);
-#endif
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
-#ifndef FOO
-	udelay(1);
-#endif
-	NCR5380_write(START_DMA_SEND_REG, 0);
-#ifndef FOO
-	udelay(1);
-#endif
-}
+	if (p & SR_IO) {
+		io_recovery_delay(1);
+		NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+	} else {
+		io_recovery_delay(1);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+		io_recovery_delay(1);
+		NCR5380_write(START_DMA_SEND_REG, 0);
+		io_recovery_delay(1);
+	}
 
 #if defined(REAL_DMA_POLL)
-do {
-	tmp = NCR5380_read(BUS_AND_STATUS_REG);
-} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR |
-
-					      BASR_END_DMA_TRANSFER)));
+	do {
+		tmp = NCR5380_read(BUS_AND_STATUS_REG);
+	} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));
 
 /*
    At this point, either we've completed DMA, or we have a phase mismatch,
@@ -2379,172 +2086,128 @@
    request.
  */
 
-if (p & SR_IO) {
+	if (p & SR_IO) {
 #ifdef READ_OVERRUNS
-	udelay(10);
-	if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
-	     (BASR_PHASE_MATCH | BASR_ACK))) {
-		saved_data = NCR5380_read(INPUT_DATA_REGISTER);
-		overrun = 1;
-	}
+		udelay(10);
+		if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) {
+			saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+			overrun = 1;
+		}
 #endif
-} else {
-	int limit = 100;
-	while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) ||
-	       (NCR5380_read(STATUS_REG) & SR_REQ)) {
-		if (!(tmp & BASR_PHASE_MATCH))
-			break;
-		if (--limit < 0)
-			break;
+	} else {
+		int limit = 100;
+		while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) {
+			if (!(tmp & BASR_PHASE_MATCH))
+				break;
+			if (--limit < 0)
+				break;
+		}
 	}
-}
 
+	dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG)));
 
-#if (NDEBUG & NDEBUG_DMA)
-printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n",
-       instance->host_no, tmp, NCR5380_read(STATUS_REG));
-#endif
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
-NCR5380_write(MODE_REG, MR_BASE);
-NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-residue = NCR5380_dma_residual(instance);
-c -= residue;
-*count -= c;
-*data += c;
-*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
+	residue = NCR5380_dma_residual(instance);
+	c -= residue;
+	*count -= c;
+	*data += c;
+	*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
 
 #ifdef READ_OVERRUNS
-if (*phase == p && (p & SR_IO) && residue == 0)
-{
-if (overrun) {
-#if (NDEBUG & NDEBUG_DMA)
-	printk("Got an input overrun, using saved byte\n");
-#endif
-	**data = saved_data;
-	*data += 1;
-	*count -= 1;
-	cnt = toPIO = 1;
-} else {
-	printk("No overrun??\n");
-	cnt = toPIO = 2;
-}
-#if (NDEBUG & NDEBUG_DMA)
-printk("Doing %d-byte PIO to 0x%X\n", cnt, *data);
-#endif
-NCR5380_transfer_pio(instance, phase, &cnt, data);
-*count -= toPIO - cnt;
-}
+	if (*phase == p && (p & SR_IO) && residue == 0) {
+		if (overrun) {
+			dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n"));
+			**data = saved_data;
+			*data += 1;
+			*count -= 1;
+			cnt = toPIO = 1;
+		} else {
+			printk("No overrun??\n");
+			cnt = toPIO = 2;
+		}
+		dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data));
+		NCR5380_transfer_pio(instance, phase, &cnt, data);
+		*count -= toPIO - cnt;
+	}
 #endif
 
-#if (NDEBUG & NDEBUG_DMA)
-printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n",
-       *data, *count, *(*data + *count - 1), *(*data + *count));
-#endif
-return 0;
+	dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count)));
+	return 0;
 
 #elif defined(REAL_DMA)
-return 0;
+	return 0;
 #else				/* defined(REAL_DMA_POLL) */
-if (p & SR_IO) {
+	if (p & SR_IO) {
 #ifdef DMA_WORKS_RIGHT
-	foo = NCR5380_pread(instance, d, c);
+		foo = NCR5380_pread(instance, d, c);
 #else
-	int diff = 1;
-	if (hostdata->flags & FLAG_NCR53C400) {
-		diff = 0;
-	}
-	if (!(foo = NCR5380_pread(instance, d, c - diff))) {
-		/*
-		 * We can't disable DMA mode after successfully transferring 
-		 * what we plan to be the last byte, since that would open up
-		 * a race condition where if the target asserted REQ before 
-		 * we got the DMA mode reset, the NCR5380 would have latched
-		 * an additional byte into the INPUT DATA register and we'd
-		 * have dropped it.
-		 * 
-		 * The workaround was to transfer one fewer bytes than we 
-		 * intended to with the pseudo-DMA read function, wait for 
-		 * the chip to latch the last byte, read it, and then disable
-		 * pseudo-DMA mode.
-		 * 
-		 * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
-		 * REQ is deasserted when ACK is asserted, and not reasserted
-		 * until ACK goes false.  Since the NCR5380 won't lower ACK
-		 * until DACK is asserted, which won't happen unless we twiddle
-		 * the DMA port or we take the NCR5380 out of DMA mode, we 
-		 * can guarantee that we won't handshake another extra 
-		 * byte.
-		 */
+		int diff = 1;
+		if (hostdata->flags & FLAG_NCR53C400) {
+			diff = 0;
+		}
+		if (!(foo = NCR5380_pread(instance, d, c - diff))) {
+			/*
+			 * We can't disable DMA mode after successfully transferring 
+			 * what we plan to be the last byte, since that would open up
+			 * a race condition where if the target asserted REQ before 
+			 * we got the DMA mode reset, the NCR5380 would have latched
+			 * an additional byte into the INPUT DATA register and we'd
+			 * have dropped it.
+			 * 
+			 * The workaround was to transfer one fewer bytes than we 
+			 * intended to with the pseudo-DMA read function, wait for 
+			 * the chip to latch the last byte, read it, and then disable
+			 * pseudo-DMA mode.
+			 * 
+			 * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
+			 * REQ is deasserted when ACK is asserted, and not reasserted
+			 * until ACK goes false.  Since the NCR5380 won't lower ACK
+			 * until DACK is asserted, which won't happen unless we twiddle
+			 * the DMA port or we take the NCR5380 out of DMA mode, we 
+			 * can guarantee that we won't handshake another extra 
+			 * byte.
+			 */
 
-		if (!(hostdata->flags & FLAG_NCR53C400)) {
-			while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
-			/* Wait for clean handshake */
-			while (NCR5380_read(STATUS_REG) & SR_REQ);
-			d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+			if (!(hostdata->flags & FLAG_NCR53C400)) {
+				while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
+				/* Wait for clean handshake */
+				while (NCR5380_read(STATUS_REG) & SR_REQ);
+				d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+			}
 		}
-	}
 #endif
-} else {
+	} else {
 #ifdef DMA_WORKS_RIGHT
-	foo = NCR5380_pwrite(instance, d, c);
+		foo = NCR5380_pwrite(instance, d, c);
 #else
-	int timeout;
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("About to pwrite %d bytes\n", c);
-#endif
-	if (!(foo = NCR5380_pwrite(instance, d, c))) {
-		/*
-		 * Wait for the last byte to be sent.  If REQ is being asserted for 
-		 * the byte we're interested, we'll ACK it and it will go false.  
-		 */
-		if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
-			timeout = 20000;
-#if 1
-#if 1
-			while (!(NCR5380_read(BUS_AND_STATUS_REG) &
-			 BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) &
-				       BASR_PHASE_MATCH));
-#else
-			if (NCR5380_read(STATUS_REG) & SR_REQ) {
-				for (; timeout &&
-				     !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
-				     --timeout);
-				for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ);
-				     --timeout);
-			}
-#endif
-
-
-#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
-			if (!timeout)
-				printk("scsi%d : timed out on last byte\n",
-				       instance->host_no);
-#endif
-
-
-			if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
-				hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
-				if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
-					hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
-#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
-					printk("scsi%d : last bit sent works\n",
-					       instance->host_no);
-#endif
+		int timeout;
+		dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c));
+		if (!(foo = NCR5380_pwrite(instance, d, c))) {
+			/*
+			 * Wait for the last byte to be sent.  If REQ is being asserted for 
+			 * the byte we're interested, we'll ACK it and it will go false.  
+			 */
+			if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
+				timeout = 20000;
+				while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));
+
+				if (!timeout)
+					dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no));
+
+				if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
+					hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
+					if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
+						hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
+						dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no));
+					}
 				}
+			} else {
+				dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n"));
+				while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
+				dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n"));
 			}
-		} else {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-			printk("Waiting for LASTBYTE\n");
-#endif
-			while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-			printk("Got LASTBYTE\n");
-#endif
-		}
-#else
-			udelay(5);
-#endif
 		}
 #endif
 	}
@@ -2552,13 +2215,9 @@
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
 	if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-		printk("53C400w: Checking for IRQ\n");
-#endif
+		dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n"));
 		if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-			printk("53C400w:    got it, reading reset interrupt reg\n");
-#endif
+			dprintk(NDEBUG_C400_PWRITE, ("53C400w:    got it, reading reset interrupt reg\n"));
 			NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 		} else {
 			printk("53C400w:    IRQ NOT THERE!\n");
@@ -2567,11 +2226,8 @@
 	*data = d + c;
 	*count = 0;
 	*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
-#if 0
-	NCR5380_print_phase(instance);
-#endif
-#if defined(PSEUDO_DMA) && !defined(UNSAFE)
-	restore_flags(flags);
+#if defined(PSEUDO_DMA) && defined(UNSAFE)
+	spin_lock_irq(&io_request_lock);
 #endif				/* defined(REAL_DMA_POLL) */
 	return foo;
 #endif				/* def REAL_DMA */
@@ -2593,12 +2249,13 @@
  *
  * XXX Note : we need to watch for bus free or a reset condition here 
  *      to recover from an unexpected bus free condition.
+ *
+ * Locks: io_request_lock held by caller
  */
 
 static void NCR5380_information_transfer(struct Scsi_Host *instance) {
 	NCR5380_local_declare();
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-	 instance->hostdata;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata;
 	unsigned char msgout = NOP;
 	int sink = 0;
 	int len;
@@ -2608,10 +2265,8 @@
 	unsigned char *data;
 	unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
 	Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
-#ifdef USLEEP
 	/* RvC: we need to set the end of the polling time */
 	unsigned long poll_time = jiffies + USLEEP_POLL;
-#endif
 
 	NCR5380_setup(instance);
 
@@ -2622,27 +2277,22 @@
 			phase = (tmp & PHASE_MASK);
 			if (phase != old_phase) {
 				old_phase = phase;
-#if (NDEBUG & NDEBUG_INFORMATION)
-				NCR5380_print_phase(instance);
-#endif
+				NCR5380_dprint_phase(NDEBUG_INFORMATION, instance);
 			}
 			if (sink && (phase != PHASE_MSGOUT)) {
 				NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
-				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
-					      ICR_ASSERT_ACK);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
 				while (NCR5380_read(STATUS_REG) & SR_REQ);
-				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-					      ICR_ASSERT_ATN);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 				sink = 0;
 				continue;
 			}
 			switch (phase) {
-				case PHASE_DATAIN:
-				    case PHASE_DATAOUT:
+			case PHASE_DATAIN:
+			case PHASE_DATAOUT:
 #if (NDEBUG & NDEBUG_NO_DATAOUT)
-				    printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n",
-					   instance->host_no);
+				printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no);
 				sink = 1;
 				do_abort(instance);
 				cmd->result = DID_ERROR << 16;
@@ -2659,11 +2309,7 @@
 					--cmd->SCp.buffers_residual;
 					cmd->SCp.this_residual = cmd->SCp.buffer->length;
 					cmd->SCp.ptr = cmd->SCp.buffer->address;
-#if (NDEBUG & NDEBUG_INFORMATION)
-					printk("scsi%d : %d bytes and %d buffers left\n",
-					       instance->host_no, cmd->SCp.this_residual,
-					       cmd->SCp.buffers_residual);
-#endif
+					dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual));
 				}
 				/*
 				 * The preferred transfer method is going to be 
@@ -2684,9 +2330,7 @@
 				 * We supplement these 2 if's with the flag.
 				 */
 #ifdef NCR5380_dma_xfer_len
-				if (!cmd->device->borken &&
-				!(hostdata->flags & FLAG_NO_PSEUDO_DMA) &&
-				    (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
+				if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
 #else
 				transfersize = cmd->transfersize;
 
@@ -2695,27 +2339,21 @@
 					transfersize = 512;
 #endif				/* LIMIT_TRANSFERSIZE */
 
-				if (!cmd->device->borken && transfersize &&
-				!(hostdata->flags & FLAG_NO_PSEUDO_DMA) &&
-				    cmd->SCp.this_residual && !(cmd->SCp.this_residual %
-							 transfersize)) {
+				if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) {
 					/* Limit transfers to 32K, for xx400 & xx406
 					 * pseudoDMA that transfers in 128 bytes blocks. */
 					if (transfersize > 32 * 1024)
 						transfersize = 32 * 1024;
 #endif
 					len = transfersize;
-					if (NCR5380_transfer_dma(instance, &phase,
-								 &len, (unsigned char **) &cmd->SCp.ptr)) {
+					if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) {
 						/*
 						 * If the watchdog timer fires, all future accesses to this
 						 * device will use the polled-IO.
 						 */
-						printk("scsi%d : switching target %d lun %d to slow handshake\n",
-						       instance->host_no, cmd->target, cmd->lun);
+						printk("scsi%d : switching target %d lun %d to slow handshake\n", instance->host_no, cmd->target, cmd->lun);
 						cmd->device->borken = 1;
-						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-							 ICR_ASSERT_ATN);
+						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 						sink = 1;
 						do_abort(instance);
 						cmd->result = DID_ERROR << 16;
@@ -2725,12 +2363,11 @@
 						cmd->SCp.this_residual -= transfersize - len;
 				} else
 #endif				/* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
-					NCR5380_transfer_pio(instance, &phase,
-							     (int *) &cmd->SCp.this_residual, (unsigned char **)
-							  &cmd->SCp.ptr);
+					NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **)
+							     &cmd->SCp.ptr);
 				break;
-				case PHASE_MSGIN:
-				    len = 1;
+			case PHASE_MSGIN:
+				len = 1;
 				data = &tmp;
 				NCR5380_transfer_pio(instance, &phase, &len, &data);
 				cmd->SCp.Message = tmp;
@@ -2747,24 +2384,18 @@
 					 * next_link, done() is called as with unlinked commands.
 					 */
 #ifdef LINKED
-					case LINKED_CMD_COMPLETE:
-					    case LINKED_FLG_CMD_COMPLETE:
+				case LINKED_CMD_COMPLETE:
+				case LINKED_FLG_CMD_COMPLETE:
 					/* Accept message by clearing ACK */
-					    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-#if (NDEBUG & NDEBUG_LINKED)
-					printk("scsi%d : target %d lun %d linked command complete.\n",
-					       instance->host_no, cmd->target, cmd->lun);
-#endif
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun));
 					/* 
 					 * Sanity check : A linked command should only terminate with
 					 * one of these messages if there are more linked commands
 					 * available.
 					 */
-
 					if (!cmd->next_link) {
-						printk("scsi%d : target %d lun %d linked command complete, no next_link\n"
-						       instance->host_no, cmd->target, cmd->lun);
+						printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->target, cmd->lun);
 						sink = 1;
 						do_abort(instance);
 						return;
@@ -2773,27 +2404,19 @@
 					/* The next command is still part of this process */
 					cmd->next_link->tag = cmd->tag;
 					cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-#if (NDEBUG & NDEBUG_LINKED)
-					printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n",
-					       instance->host_no, cmd->target, cmd->lun);
-#endif
-#ifdef NCR5380_STATS
+					dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun));
 					collect_stats(hostdata, cmd);
-#endif
 					cmd->scsi_done(cmd);
 					cmd = hostdata->connected;
 					break;
 #endif				/* def LINKED */
-					case ABORT:
-					    case COMMAND_COMPLETE:
+				case ABORT:
+				case COMMAND_COMPLETE:
 					/* Accept message by clearing ACK */
-					    sink = 1;
+					sink = 1;
 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 					hostdata->connected = NULL;
-#if (NDEBUG & NDEBUG_QUEUES)
-					printk("scsi%d : command for target %d, lun %d completed\n",
-					       instance->host_no, cmd->target, cmd->lun);
-#endif
+					dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun));
 					hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
 
 					/* 
@@ -2818,13 +2441,8 @@
 						cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
 
 #ifdef AUTOSENSE
-					if ((cmd->cmnd[0] != REQUEST_SENSE) &&
-					    (cmd->SCp.Status == CHECK_CONDITION)) {
-						unsigned long flags;
-#if (NDEBUG & NDEBUG_AUTOSENSE)
-						printk("scsi%d : performing request sense\n",
-						       instance->host_no);
-#endif
+					if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) {
+						dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
 						cmd->cmnd[0] = REQUEST_SENSE;
 						cmd->cmnd[1] &= 0xe0;
 						cmd->cmnd[2] = 0;
@@ -2837,21 +2455,14 @@
 						cmd->SCp.ptr = (char *) cmd->sense_buffer;
 						cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
 
-						save_flags(flags);
-						cli();
 						LIST(cmd, hostdata->issue_queue);
 						cmd->host_scribble = (unsigned char *)
 						    hostdata->issue_queue;
 						hostdata->issue_queue = (Scsi_Cmnd *) cmd;
-						restore_flags(flags);
-#if (NDEBUG & NDEBUG_QUEUES)
-						printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no);
-#endif
+						dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no));
 					} else {
 #endif				/* def AUTOSENSE */
-#ifdef NCR5380_STATS
 						collect_stats(hostdata, cmd);
-#endif
 						cmd->scsi_done(cmd);
 					}
 
@@ -2865,37 +2476,29 @@
 					while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
 						barrier();
 					return;
-					case MESSAGE_REJECT:
+				case MESSAGE_REJECT:
 					/* Accept message by clearing ACK */
-					    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 					switch (hostdata->last_message) {
-						case HEAD_OF_QUEUE_TAG:
-						    case ORDERED_QUEUE_TAG:
-						    case SIMPLE_QUEUE_TAG:
-						    cmd->device->tagged_queue = 0;
+					case HEAD_OF_QUEUE_TAG:
+					case ORDERED_QUEUE_TAG:
+					case SIMPLE_QUEUE_TAG:
+						cmd->device->tagged_queue = 0;
 						hostdata->busy[cmd->target] |= (1 << cmd->lun);
 						break;
-						default:
-						    break;
+					default:
+						break;
 					}
-					case DISCONNECT: {
-						unsigned long flags;
+				case DISCONNECT:{
 						/* Accept message by clearing ACK */
 						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 						cmd->device->disconnect = 1;
-						save_flags(flags);
-						cli();
 						LIST(cmd, hostdata->disconnected_queue);
 						cmd->host_scribble = (unsigned char *)
 						    hostdata->disconnected_queue;
 						hostdata->connected = NULL;
 						hostdata->disconnected_queue = cmd;
-						restore_flags(flags);
-#if (NDEBUG & NDEBUG_QUEUES)
-						printk("scsi%d : command for target %d lun %d was moved from connected to"
-						       "  the disconnected_queue\n", instance->host_no,
-						  cmd->target, cmd->lun);
-#endif
+						dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" "  the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun));
 						/* 
 						 * Restore phase bits to 0 so an interrupted selection, 
 						 * arbitration can resume.
@@ -2907,9 +2510,6 @@
 						/* Wait for bus free to avoid nasty timeouts */
 						while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
 							barrier();
-#if 0
-						NCR5380_print_status(instance);
-#endif
 						return;
 					}
 					/* 
@@ -2922,12 +2522,12 @@
 					 * disconnecting, and we have to break spec to remain 
 					 * compatible.
 					 */
-					case SAVE_POINTERS:
-					    case RESTORE_POINTERS:
+				case SAVE_POINTERS:
+				case RESTORE_POINTERS:
 					/* Accept message by clearing ACK */
-					    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 					break;
-					case EXTENDED_MESSAGE:
+				case EXTENDED_MESSAGE:
 /* 
  * Extended messages are sent in the following format :
  * Byte         
@@ -2940,28 +2540,19 @@
  * Start the extended message buffer with the EXTENDED_MESSAGE
  * byte, since print_msg() wants the whole thing.  
  */
-					    extended_msg[0] = EXTENDED_MESSAGE;
+					extended_msg[0] = EXTENDED_MESSAGE;
 					/* Accept first byte by clearing ACK */
 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-#if (NDEBUG & NDEBUG_EXTENDED)
-					printk("scsi%d : receiving extended message\n",
-					       instance->host_no);
-#endif
+					dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no));
 
 					len = 2;
 					data = extended_msg + 1;
 					phase = PHASE_MSGIN;
 					NCR5380_transfer_pio(instance, &phase, &len, &data);
 
-#if (NDEBUG & NDEBUG_EXTENDED)
-					printk("scsi%d : length=%d, code=0x%02x\n",
-					       instance->host_no, (int) extended_msg[1],
-					       (int) extended_msg[2]);
-#endif
+					dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]));
 
-					if (!len && extended_msg[1] <=
-					    (sizeof(extended_msg) - 1)) {
+					if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) {
 						/* Accept third byte by clearing ACK */
 						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 						len = extended_msg[1] - 1;
@@ -2969,26 +2560,20 @@
 						phase = PHASE_MSGIN;
 
 						NCR5380_transfer_pio(instance, &phase, &len, &data);
-
-#if (NDEBUG & NDEBUG_EXTENDED)
-						printk("scsi%d : message received, residual %d\n",
-						 instance->host_no, len);
-#endif
+						dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len));
 
 						switch (extended_msg[2]) {
-							case EXTENDED_SDTR:
-							    case EXTENDED_WDTR:
-							    case EXTENDED_MODIFY_DATA_POINTER:
-							    case EXTENDED_EXTENDED_IDENTIFY:
-							    tmp = 0;
+						case EXTENDED_SDTR:
+						case EXTENDED_WDTR:
+						case EXTENDED_MODIFY_DATA_POINTER:
+						case EXTENDED_EXTENDED_IDENTIFY:
+							tmp = 0;
 						}
 					} else if (len) {
-						printk("scsi%d: error receiving extended message\n",
-						       instance->host_no);
+						printk("scsi%d: error receiving extended message\n", instance->host_no);
 						tmp = 0;
 					} else {
-						printk("scsi%d: extended message code %02x length %d is too long\n",
-						       instance->host_no, extended_msg[2], extended_msg[1]);
+						printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]);
 						tmp = 0;
 					}
 					/* Fall through to reject message */
@@ -2997,26 +2582,23 @@
 					 * If we get something weird that we aren't expecting, 
 					 * reject it.
 					 */
-					default:
-					    if (!tmp) {
+				default:
+					if (!tmp) {
 						printk("scsi%d: rejecting message ", instance->host_no);
 						print_msg(extended_msg);
 						printk("\n");
 					} else if (tmp != EXTENDED_MESSAGE)
-						printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n",
-						       instance->host_no, tmp, cmd->target, cmd->lun);
+						printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", instance->host_no, tmp, cmd->target, cmd->lun);
 					else
-						printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n",
-						       instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun);
+						printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun);
 
 					msgout = MESSAGE_REJECT;
-					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-						      ICR_ASSERT_ATN);
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 					break;
 				}	/* switch (tmp) */
 				break;
-				case PHASE_MSGOUT:
-				    len = 1;
+			case PHASE_MSGOUT:
+				len = 1;
 				data = &msgout;
 				hostdata->last_message = msgout;
 				NCR5380_transfer_pio(instance, &phase, &len, &data);
@@ -3024,69 +2606,50 @@
 					hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
 					hostdata->connected = NULL;
 					cmd->result = DID_ERROR << 16;
-#ifdef NCR5380_STATS
 					collect_stats(hostdata, cmd);
-#endif
 					cmd->scsi_done(cmd);
 					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 					return;
 				}
 				msgout = NOP;
 				break;
-				case PHASE_CMDOUT:
-				    len = cmd->cmd_len;
+			case PHASE_CMDOUT:
+				len = cmd->cmd_len;
 				data = cmd->cmnd;
 				/* 
 				 * XXX for performance reasons, on machines with a 
 				 * PSEUDO-DMA architecture we should probably 
 				 * use the dma transfer function.  
 				 */
-				NCR5380_transfer_pio(instance, &phase, &len,
-						     &data);
-#ifdef USLEEP
-				if (!cmd->device->disconnect &&
-					should_disconnect(cmd->cmnd[0])) 
-				{
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) {
 					hostdata->time_expires = jiffies + USLEEP_SLEEP;
-#if (NDEBUG & NDEBUG_USLEEP)
-					printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no,
-					       hostdata->time_expires);
-#endif
+					dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires));
 					NCR5380_set_timer(instance);
 					return;
 				}
-#endif				/* def USLEEP */
 				break;
-				case PHASE_STATIN:
-				    len = 1;
+			case PHASE_STATIN:
+				len = 1;
 				data = &tmp;
 				NCR5380_transfer_pio(instance, &phase, &len, &data);
 				cmd->SCp.Status = tmp;
 				break;
-				default:
-				    printk("scsi%d : unknown phase\n", instance->host_no);
-#ifdef NDEBUG
-				NCR5380_print(instance);
-#endif
+			default:
+				printk("scsi%d : unknown phase\n", instance->host_no);
+				NCR5380_dprint(NDEBUG_ALL, instance);
 			}	/* switch(phase) */
 		}		/* if (tmp * SR_REQ) */
-#ifdef USLEEP
-		else 
-		{
+		else {
 			/* RvC: go to sleep if polling time expired
 			 */
-			if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time))
-			{
+			if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) {
 				hostdata->time_expires = jiffies + USLEEP_SLEEP;
-#if (NDEBUG & NDEBUG_USLEEP)
-				printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no,
-				       hostdata->time_expires);
-#endif
+				dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires));
 				NCR5380_set_timer(instance);
 				return;
 			}
 		}
-#endif
 	}			/* while (1) */
 }
 
@@ -3099,9 +2662,9 @@
  *      
  * Inputs : instance - this instance of the NCR5380.
  *
+ * Locks: io_request_lock held by caller
  */
 
-
 static void NCR5380_reselect(struct Scsi_Host *instance) {
 	NCR5380_local_declare();
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
@@ -3109,28 +2672,22 @@
 	unsigned char target_mask;
 	unsigned char lun, phase;
 	int len;
-#ifdef SCSI2
-	unsigned char tag;
-#endif
 	unsigned char msg[3];
 	unsigned char *data;
 	Scsi_Cmnd *tmp = NULL, *prev;
 	int abort = 0;
-	 NCR5380_setup(instance);
+	NCR5380_setup(instance);
 
 	/*
 	 * Disable arbitration, etc. since the host adapter obviously
 	 * lost, and tell an interrupted NCR5380_select() to restart.
 	 */
 
-	 NCR5380_write(MODE_REG, MR_BASE);
-	 hostdata->restart_select = 1;
-
-	 target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+	NCR5380_write(MODE_REG, MR_BASE);
+	hostdata->restart_select = 1;
 
-#if (NDEBUG & NDEBUG_RESELECTION)
-	 printk("scsi%d : reselect\n", instance->host_no);
-#endif
+	target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+	dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no));
 
 	/* 
 	 * At this point, we have detected that our SCSI ID is on the bus,
@@ -3141,10 +2698,10 @@
 	 * signal.
 	 */
 
-	 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
 
 	while (NCR5380_read(STATUS_REG) & SR_SEL);
-	 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
 	/*
 	 * Wait for target to go into MSGIN.
@@ -3152,15 +2709,13 @@
 
 	while (!(NCR5380_read(STATUS_REG) & SR_REQ));
 
-	 len = 1;
-	 data = msg;
-	 phase = PHASE_MSGIN;
-	 NCR5380_transfer_pio(instance, &phase, &len, &data);
-
+	len = 1;
+	data = msg;
+	phase = PHASE_MSGIN;
+	NCR5380_transfer_pio(instance, &phase, &len, &data);
 
 	if (!msg[0] & 0x80) {
-		printk("scsi%d : expecting IDENTIFY message, got ",
-		       instance->host_no);
+		printk("scsi%d : expecting IDENTIFY message, got ", instance->host_no);
 		print_msg(msg);
 		abort = 1;
 	} else {
@@ -3174,22 +2729,14 @@
 		 * nexuses so we can chose to do additional data transfer.
 		 */
 
-#ifdef SCSI2
-#error "SCSI-II tagged queueing is not supported yet"
-#endif
-
 		/* 
 		 * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
 		 * just reestablished, and remove it from the disconnected queue.
 		 */
 
 
-		for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
-		 tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
+		for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
 			if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
-#ifdef SCSI2
-			    && (tag == tmp->tag)
-#endif
 			    ) {
 				if (prev) {
 					REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
@@ -3202,13 +2749,7 @@
 				break;
 			}
 		if (!tmp) {
-#ifdef SCSI2
-			printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n",
-			       instance->host_no, target_mask, lun, tag);
-#else
-			printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n",
-			       instance->host_no, target_mask, lun);
-#endif
+			printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
 			/* 
 			 * Since we have an established nexus that we can't do anything with,
 			 * we must abort it.  
@@ -3221,10 +2762,7 @@
 		do_abort(instance);
 	} else {
 		hostdata->connected = tmp;
-#if (NDEBUG & NDEBUG_RESELECTION)
-		printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n",
-		     instance->host_no, tmp->target, tmp->lun, tmp->tag);
-#endif
+		dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag));
 	}
 }
 
@@ -3243,8 +2781,7 @@
 #ifdef REAL_DMA
 static void NCR5380_dma_complete(NCR5380_instance * instance) {
 	NCR5380_local_declare();
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *
-					     instance->hostdata);
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * instance->hostdata);
 	int transferred;
 	NCR5380_setup(instance);
 
@@ -3287,10 +2824,12 @@
  *
  * Returns : 0 - success, -1 on failure.
  *
- * XXX - there is no way to abort the command that is currently 
- *       connected, you have to wait for it to complete.  If this is 
- *       a problem, we could implement longjmp() / setjmp(), setjmp()
- *       called where the loop started in NCR5380_main().
+ *	XXX - there is no way to abort the command that is currently 
+ *	connected, you have to wait for it to complete.  If this is 
+ *	a problem, we could implement longjmp() / setjmp(), setjmp()
+ *	called where the loop started in NCR5380_main().
+ *
+ *	Locks: io_request_lock held by caller
  */
 
 #ifndef NCR5380_abort
@@ -3298,10 +2837,8 @@
 #endif
 int NCR5380_abort(Scsi_Cmnd * cmd) {
 	NCR5380_local_declare();
-	unsigned long flags;
 	struct Scsi_Host *instance = cmd->host;
-	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-	 instance->hostdata;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	Scsi_Cmnd *tmp, **prev;
 
 	printk("scsi%d : aborting command\n", instance->host_no);
@@ -3314,15 +2851,10 @@
 
 	NCR5380_print_status(instance);
 
-	save_flags(flags);
-	cli();
 	NCR5380_setup(instance);
 
-#if (NDEBUG & NDEBUG_ABORT)
-	printk("scsi%d : abort called\n", instance->host_no);
-	printk("        basr 0x%X, sr 0x%X\n",
-	     NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG));
-#endif
+	dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no));
+	dprintk(NDEBUG_ABORT, ("        basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)));
 
 #if 0
 /*
@@ -3332,9 +2864,7 @@
  */
 
 	if (hostdata->connected == cmd) {
-#if (NDEBUG & NDEBUG_ABORT)
-		printk("scsi%d : aborting connected command\n", instance->host_no);
-#endif
+		dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no));
 		hostdata->aborted = 1;
 /*
  * We should perform BSY checking, and make sure we haven't slipped
@@ -3361,24 +2891,15 @@
  * Case 2 : If the command hasn't been issued yet, we simply remove it 
  *          from the issue queue.
  */
-#if (NDEBUG & NDEBUG_ABORT)
 	/* KLL */
-	printk("scsi%d : abort going into loop.\n", instance->host_no);
-#endif
-	for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue),
-	     tmp = (Scsi_Cmnd *) hostdata->issue_queue;
-	     tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp =
-	     (Scsi_Cmnd *) tmp->host_scribble)
+	dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no));
+	for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
 		if (cmd == tmp) {
 			REMOVE(5, *prev, tmp, tmp->host_scribble);
 			(*prev) = (Scsi_Cmnd *) tmp->host_scribble;
 			tmp->host_scribble = NULL;
 			tmp->result = DID_ABORT << 16;
-			restore_flags(flags);
-#if (NDEBUG & NDEBUG_ABORT)
-			printk("scsi%d : abort removed command from issue queue.\n",
-			       instance->host_no);
-#endif
+			dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
 			tmp->done(tmp);
 			return SCSI_ABORT_SUCCESS;
 		}
@@ -3400,10 +2921,7 @@
  */
 
 	if (hostdata->connected) {
-		restore_flags(flags);
-#if (NDEBUG & NDEBUG_ABORT)
-		printk("scsi%d : abort failed, command connected.\n", instance->host_no);
-#endif
+		dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no));
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 /*
@@ -3431,34 +2949,22 @@
  * it from the disconnected queue.
  */
 
-	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
-	     tmp = (Scsi_Cmnd *) tmp->host_scribble)
+	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
 		if (cmd == tmp) {
-			restore_flags(flags);
-#if (NDEBUG & NDEBUG_ABORT)
-			printk("scsi%d : aborting disconnected command.\n", instance->host_no);
-#endif
+			dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no));
 
 			if (NCR5380_select(instance, cmd, (int) cmd->tag))
 				return SCSI_ABORT_BUSY;
-
-#if (NDEBUG & NDEBUG_ABORT)
-			printk("scsi%d : nexus reestablished.\n", instance->host_no);
-#endif
+			dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no));
 
 			do_abort(instance);
 
-			cli();
-			for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue),
-			tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
-			     tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp =
-			     (Scsi_Cmnd *) tmp->host_scribble)
+			for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
 				if (cmd == tmp) {
 					REMOVE(5, *prev, tmp, tmp->host_scribble);
 					*prev = (Scsi_Cmnd *) tmp->host_scribble;
 					tmp->host_scribble = NULL;
 					tmp->result = DID_ABORT << 16;
-					restore_flags(flags);
 					tmp->done(tmp);
 					return SCSI_ABORT_SUCCESS;
 				}
@@ -3472,10 +2978,7 @@
  * so we won't panic, but we will notify the user in case something really
  * broke.
  */
-
-	restore_flags(flags);
-	printk("scsi%d : warning : SCSI command probably completed successfully\n"
-	       "         before abortion\n", instance->host_no);
+	printk("scsi%d : warning : SCSI command probably completed successfully\n" "         before abortion\n", instance->host_no);
 	return SCSI_ABORT_NOT_RUNNING;
 }
 
@@ -3487,6 +2990,7 @@
  *
  * Returns : SCSI_RESET_WAKEUP
  *
+ * Locks: io_request_lock held by caller
  */
 
 #ifndef NCR5380_reset
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- linux-2.4.16/drivers/scsi/NCR5380.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/NCR5380.h	Fri Dec  7 19:47:12 2001
@@ -55,6 +55,8 @@
 #define NDEBUG_C400_PWRITE	0x200000
 #define NDEBUG_LISTS		0x400000
 
+#define NDEBUG_ANY		0xFFFFFFFFUL
+
 /* 
  * The contents of the OUTPUT DATA register are asserted on the bus when
  * either arbitration is occurring or the phase-indicating signals (
@@ -62,8 +64,8 @@
  * bit in the INITIATOR COMMAND register is set.
  */
 
-#define OUTPUT_DATA_REG         0       /* wo DATA lines on SCSI bus */
-#define CURRENT_SCSI_DATA_REG   0       /* ro same */
+#define OUTPUT_DATA_REG         0	/* wo DATA lines on SCSI bus */
+#define CURRENT_SCSI_DATA_REG   0	/* ro same */
 
 #define INITIATOR_COMMAND_REG	1	/* rw */
 #define ICR_ASSERT_RST		0x80	/* rw Set to assert RST  */
@@ -91,10 +93,10 @@
  */
 #define MR_BLOCK_DMA_MODE	0x80	/* rw block mode DMA */
 #define MR_TARGET		0x40	/* rw target mode */
-#define MR_ENABLE_PAR_CHECK   0x20	/* rw enable parity checking */
+#define MR_ENABLE_PAR_CHECK	0x20	/* rw enable parity checking */
 #define MR_ENABLE_PAR_INTR	0x10	/* rw enable bad parity interrupt */
 #define MR_ENABLE_EOP_INTR	0x08	/* rw enable eop interrupt */
-#define MR_MONITOR_BSY	0x04	/* rw enable int on unexpected bsy fail */
+#define MR_MONITOR_BSY		0x04	/* rw enable int on unexpected bsy fail */
 #define MR_DMA_MODE		0x02	/* rw DMA / pseudo DMA mode */
 #define MR_ARBITRATE		0x01	/* rw start arbitration */
 
@@ -116,7 +118,7 @@
  * Note : a set bit indicates an active signal, driven by us or another 
  * device.
  */
-#define SR_RST			0x80	
+#define SR_RST			0x80
 #define SR_BSY			0x40
 #define SR_REQ			0x20
 #define SR_MSG			0x10
@@ -159,17 +161,17 @@
 /* Write any value to this register to start an ini mode DMA receive */
 #define START_DMA_INITIATOR_RECEIVE_REG 7	/* wo */
 
-#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8      /* rw */
+#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8	/* rw */
 
-#define CSR_RESET              0x80    /* wo  Resets 53c400 */
-#define CSR_53C80_REG          0x80    /* ro  5380 registers busy */
-#define CSR_TRANS_DIR          0x40    /* rw  Data transfer direction */
-#define CSR_SCSI_BUFF_INTR     0x20    /* rw  Enable int on transfer ready */
-#define CSR_53C80_INTR         0x10    /* rw  Enable 53c80 interrupts */
-#define CSR_SHARED_INTR        0x08    /* rw  Interrupt sharing */
-#define CSR_HOST_BUF_NOT_RDY   0x04    /* ro  Is Host buffer ready */
-#define CSR_SCSI_BUF_RDY       0x02    /* ro  SCSI buffer read */
-#define CSR_GATED_53C80_IRQ    0x01    /* ro  Last block xferred */
+#define CSR_RESET              0x80	/* wo  Resets 53c400 */
+#define CSR_53C80_REG          0x80	/* ro  5380 registers busy */
+#define CSR_TRANS_DIR          0x40	/* rw  Data transfer direction */
+#define CSR_SCSI_BUFF_INTR     0x20	/* rw  Enable int on transfer ready */
+#define CSR_53C80_INTR         0x10	/* rw  Enable 53c80 interrupts */
+#define CSR_SHARED_INTR        0x08	/* rw  Interrupt sharing */
+#define CSR_HOST_BUF_NOT_RDY   0x04	/* ro  Is Host buffer ready */
+#define CSR_SCSI_BUF_RDY       0x02	/* ro  SCSI buffer read */
+#define CSR_GATED_53C80_IRQ    0x01	/* ro  Last block xferred */
 
 #if 0
 #define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR
@@ -178,13 +180,13 @@
 #endif
 
 /* Number of 128-byte blocks to be transferred */
-#define C400_BLOCK_COUNTER_REG   NCR53C400_register_offset-7      /* rw */
+#define C400_BLOCK_COUNTER_REG   NCR53C400_register_offset-7	/* rw */
 
 /* Resume transfer after disconnect */
-#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6      /* wo */
+#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6	/* wo */
 
 /* Access to host buffer stack */
-#define C400_HOST_BUFFER         NCR53C400_register_offset-4      /* rw */
+#define C400_HOST_BUFFER         NCR53C400_register_offset-4	/* rw */
 
 
 /* Note : PHASE_* macros are based on the values of the STATUS register */
@@ -203,8 +205,8 @@
  * the target register so we can get phase mismatch interrupts on DMA 
  * transfers.
  */
- 
-#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)	
+
+#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)
 
 /*
  * The internal should_disconnect() function returns these based on the 
@@ -220,7 +222,7 @@
  * These are "special" values for the tag parameter passed to NCR5380_select.
  */
 
-#define TAG_NEXT	-1 	/* Use next free tag */
+#define TAG_NEXT	-1	/* Use next free tag */
 #define TAG_NONE	-2	/* 
 				 * Establish I_T_L nexus instead of I_T_L_Q
 				 * even on SCSI-II devices.
@@ -235,7 +237,7 @@
 #define DMA_NONE	255
 #define IRQ_AUTO	254
 #define DMA_AUTO	254
-#define PORT_AUTO	0xffff		/* autoprobe io port for 53c400a */
+#define PORT_AUTO	0xffff	/* autoprobe io port for 53c400a */
 
 #define FLAG_HAS_LAST_BYTE_SENT		1	/* NCR53c81 or better */
 #define FLAG_CHECK_LAST_BYTE_SENT	2	/* Only test once */
@@ -245,134 +247,188 @@
 
 #ifndef ASM
 struct NCR5380_hostdata {
-    NCR5380_implementation_fields;		/* implementation specific */
-    unsigned char id_mask, id_higher_mask;	/* 1 << id, all bits greater */
-    unsigned char targets_present;		/* targets we have connected
+	NCR5380_implementation_fields;		/* implementation specific */
+	unsigned char id_mask, id_higher_mask;	/* 1 << id, all bits greater */
+	unsigned char targets_present;		/* targets we have connected
 						   to, so we can call a select
 						   failure a retryable condition */
-    volatile unsigned char busy[8];		/* index = target, bit = lun */
+	volatile unsigned char busy[8];		/* index = target, bit = lun */
 #if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-    volatile int dma_len;			/* requested length of DMA */
+	volatile int dma_len;			/* requested length of DMA */
 #endif
-    volatile unsigned char last_message;	/* last message OUT */
-    volatile Scsi_Cmnd *connected;		/* currently connected command */
-    volatile Scsi_Cmnd *issue_queue;		/* waiting to be issued */
-    volatile Scsi_Cmnd *disconnected_queue;	/* waiting for reconnect */
-    volatile int restart_select;		/* we have disconnected,
+	volatile unsigned char last_message;	/* last message OUT */
+	volatile Scsi_Cmnd *connected;		/* currently connected command */
+	volatile Scsi_Cmnd *issue_queue;	/* waiting to be issued */
+	volatile Scsi_Cmnd *disconnected_queue;	/* waiting for reconnect */
+	volatile int restart_select;		/* we have disconnected,
 						   used to restart 
 						   NCR5380_select() */
-    volatile unsigned aborted:1;		/* flag, says aborted */
-    int flags;
-#ifdef USLEEP
-    unsigned long time_expires;			/* in jiffies, set prior to sleeping */
-    struct Scsi_Host *next_timer;
-    int select_time;				/* timer in select for target response */
-    volatile Scsi_Cmnd *selecting;
-#endif
+	volatile unsigned aborted:1;		/* flag, says aborted */
+	int flags;
+	unsigned long time_expires;		/* in jiffies, set prior to sleeping */
+	struct Scsi_Host *next_timer;
+	int select_time;			/* timer in select for target response */
+	volatile Scsi_Cmnd *selecting;
 #ifdef NCR5380_STATS
-    unsigned timebase;				/* Base for time calcs */
-    long time_read[8];				/* time to do reads */
-    long time_write[8];				/* time to do writes */
-    unsigned long bytes_read[8];		/* bytes read */
-    unsigned long bytes_write[8];		/* bytes written */
-    unsigned pendingr;
-    unsigned pendingw;
+	unsigned timebase;			/* Base for time calcs */
+	long time_read[8];			/* time to do reads */
+	long time_write[8];			/* time to do writes */
+	unsigned long bytes_read[8];		/* bytes read */
+	unsigned long bytes_write[8];		/* bytes written */
+	unsigned pendingr;
+	unsigned pendingw;
 #endif
 };
 
 #ifdef __KERNEL__
-static struct Scsi_Host *first_instance;		/* linked list of 5380's */
+static struct Scsi_Host *first_instance;	/* linked list of 5380's */
+
+#define dprintk(a,b)			do {} while(0)
+#define NCR5380_dprint(a,b)		do {} while(0)
+#define NCR5380_dprint_phase(a,b)	do {} while(0)
 
 #if defined(AUTOPROBE_IRQ)
-static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible);
+static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible);
 #endif
-static void NCR5380_init (struct Scsi_Host *instance, int flags);
-static void NCR5380_information_transfer (struct Scsi_Host *instance);
+static void NCR5380_init(struct Scsi_Host *instance, int flags);
+static void NCR5380_information_transfer(struct Scsi_Host *instance);
 #ifndef DONT_USE_INTR
-static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
-static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
+static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs);
 #endif
-static void NCR5380_main (void);
-static void NCR5380_print_options (struct Scsi_Host *instance);
-static void NCR5380_print_phase (struct Scsi_Host *instance);
-static void NCR5380_print (struct Scsi_Host *instance);
+static void NCR5380_main(void);
+static void NCR5380_print_options(struct Scsi_Host *instance);
+static void NCR5380_print_phase(struct Scsi_Host *instance);
+static void NCR5380_print(struct Scsi_Host *instance);
 #ifndef NCR5380_abort
 static
 #endif
-int NCR5380_abort (Scsi_Cmnd *cmd);
+int NCR5380_abort(Scsi_Cmnd * cmd);
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags);
+int NCR5380_reset(Scsi_Cmnd * cmd, unsigned int reset_flags);
 #ifndef NCR5380_queue_command
-static 
+static
 #endif
-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
 
 
-static void NCR5380_reselect (struct Scsi_Host *instance);
-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag);
+static void NCR5380_reselect(struct Scsi_Host *instance);
+static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
 #if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
-static int NCR5380_transfer_dma (struct Scsi_Host *instance,
-	unsigned char *phase, int *count, unsigned char **data);
+static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
 #endif
-static int NCR5380_transfer_pio (struct Scsi_Host *instance,
-	unsigned char *phase, int *count, unsigned char **data);
+static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
 
 #if (defined(REAL_DMA) || defined(REAL_DMA_POLL))
 
 #if defined(i386) || defined(__alpha__)
 
-static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance,
-	unsigned char *ptr, unsigned int count, unsigned char mode) {
-    unsigned limit;
-    unsigned long bus_addr = virt_to_bus(ptr);
-
-    if (instance->dma_channel <=3) {
-	if (count > 65536)
-	    count = 65536;
-	limit = 65536 - (bus_addr & 0xFFFF);
-    } else {
-	if (count > 65536 * 2) 
-	    count = 65536 * 2;
-	limit = 65536* 2 - (bus_addr & 0x1FFFF);
-    }
-
-    if (count > limit) count = limit;
-
-    if ((count & 1) || (bus_addr & 1))
-	panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
-    cli();
-    disable_dma(instance->dma_channel);
-    clear_dma_ff(instance->dma_channel);
-    set_dma_addr(instance->dma_channel, bus_addr);
-    set_dma_count(instance->dma_channel, count);
-    set_dma_mode(instance->dma_channel, mode);
-    enable_dma(instance->dma_channel);
-    sti();
-    return count;
+/**
+ *	NCR5380_pc_dma_setup		-	setup ISA DMA
+ *	@instance: adapter to set up
+ *	@ptr: block to transfer (virtual address)
+ *	@count: number of bytes to transfer
+ *	@mode: DMA controller mode to use
+ *
+ *	Program the DMA controller ready to perform an ISA DMA transfer
+ *	on this chip.
+ *
+ *	Locks: takes and releases the ISA DMA lock.
+ */
+ 
+static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode)
+{
+	unsigned limit;
+	unsigned long bus_addr = virt_to_bus(ptr);
+	unsigned long flags;
+
+	if (instance->dma_channel <= 3) {
+		if (count > 65536)
+			count = 65536;
+		limit = 65536 - (bus_addr & 0xFFFF);
+	} else {
+		if (count > 65536 * 2)
+			count = 65536 * 2;
+		limit = 65536 * 2 - (bus_addr & 0x1FFFF);
+	}
+
+	if (count > limit)
+		count = limit;
+
+	if ((count & 1) || (bus_addr & 1))
+		panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
+	
+	flags=claim_dma_lock();
+	disable_dma(instance->dma_channel);
+	clear_dma_ff(instance->dma_channel);
+	set_dma_addr(instance->dma_channel, bus_addr);
+	set_dma_count(instance->dma_channel, count);
+	set_dma_mode(instance->dma_channel, mode);
+	enable_dma(instance->dma_channel);
+	release_dma_lock(flags);
+	
+	return count;
 }
 
-static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance,
-    unsigned char *src, unsigned int count) {
-    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE);
+/**
+ *	NCR5380_pc_dma_write_setup		-	setup ISA DMA write
+ *	@instance: adapter to set up
+ *	@ptr: block to transfer (virtual address)
+ *	@count: number of bytes to transfer
+ *
+ *	Program the DMA controller ready to perform an ISA DMA write to the
+ *	SCSI controller.
+ *
+ *	Locks: called routines take and release the ISA DMA lock.
+ */
+
+static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count)
+{
+	return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE);
 }
 
-static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance,
-    unsigned char *src, unsigned int count) {
-    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ);
+/**
+ *	NCR5380_pc_dma_read_setup		-	setup ISA DMA read
+ *	@instance: adapter to set up
+ *	@ptr: block to transfer (virtual address)
+ *	@count: number of bytes to transfer
+ *
+ *	Program the DMA controller ready to perform an ISA DMA read from the
+ *	SCSI controller.
+ *
+ *	Locks: called routines take and release the ISA DMA lock.
+ */
+
+static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count)
+{
+	return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ);
 }
 
-static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) {
-    register int tmp;
-    cli();
-    clear_dma_ff(instance->dma_channel);
-    tmp = get_dma_residue(instance->dma_channel);
-    sti();
-    return tmp;
+/**
+ *	NCR5380_pc_dma_residual		-	return bytes left 
+ *	@instance: adapter
+ *
+ *	Reports the number of bytes left over after the DMA was terminated.
+ *
+ *	Locks: takes and releases the ISA DMA lock.
+ */
+
+static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance)
+{
+	unsigned long flags;
+	int tmp;
+
+	flags = claim_dma_lock();
+	clear_dma_ff(instance->dma_channel);
+	tmp = get_dma_residue(instance->dma_channel);
+	release_dma_lock(flags);
+	
+	return tmp;
 }
-#endif /* defined(i386) || defined(__alpha__) */
-#endif /* defined(REAL_DMA)  */
-#endif /* __KERNEL__ */
-#endif /* ndef ASM */
-#endif /* NCR5380_H */
+#endif				/* defined(i386) || defined(__alpha__) */
+#endif				/* defined(REAL_DMA)  */
+#endif				/* __KERNEL__ */
+#endif				/* ndef ASM */
+#endif				/* NCR5380_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- linux-2.4.16/drivers/scsi/README.ncr53c8xx	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/README.ncr53c8xx	Wed Dec  5 20:22:25 2001
@@ -1,6 +1,6 @@
 The Linux NCR53C8XX/SYM53C8XX drivers README file
 
-Written by Gerard Roudier <groudier@club-internet.fr>
+Written by Gerard Roudier <groudier@free.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
@@ -87,7 +87,7 @@
 
 The initial Linux ncr53c8xx driver has been a port of the ncr driver from 
 FreeBSD that has been achieved in November 1995 by:
-          Gerard Roudier              <groudier@club-internet.fr>
+          Gerard Roudier              <groudier@free.fr>
 
 The original driver has been written for 386bsd and FreeBSD by:
           Wolfgang Stanglmeier        <wolf@cologne.de>
@@ -1287,7 +1287,7 @@
 be sure I will receive it.  Obviously, a bug in the driver code is
 possible.
 
-     My email address: Gerard Roudier <groudier@club-internet.fr>
+     My email address: Gerard Roudier <groudier@free.fr>
 
 Allowing disconnections is important if you use several devices on
 your SCSI bus but often causes problems with buggy devices.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/Makefile linux/drivers/scsi/aacraid/Makefile
--- linux-2.4.16/drivers/scsi/aacraid/Makefile	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/Makefile	Mon Dec 10 19:30:50 2001
@@ -0,0 +1,16 @@
+
+EXTRA_CFLAGS	+= -I$(TOPDIR)/drivers/scsi
+
+
+O_TARGET	:= dummy.o
+
+list-multi	:= aacraid.o
+aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
+		   dpcsup.o rx.o sap1sup.o
+
+obj-$(CONFIG_SCSI_AACRAID) += aacraid.o
+
+include $(TOPDIR)/Rules.make
+
+aacraid.o: $(aacraid-objs)
+	$(LD) -r -o $@ $(aacraid-objs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/README linux/drivers/scsi/aacraid/README
--- linux-2.4.16/drivers/scsi/aacraid/README	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/README	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,41 @@
+AACRAID Driver for Linux (take two)
+
+Introduction
+-------------------------
+The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+OEM based RAID controllers. This is a major rewrite from the original 
+Adaptec supplied driver. It has signficantly cleaned up both the code
+and the running binary size (the module is less than half the size of
+the original).
+
+This driver is experimental.
+
+Supported Cards/Chipsets
+-------------------------
+	Dell Computer Corporation PERC 2 Quad Channel
+	Dell Computer Corporation PERC 2/Si
+	Dell Computer Corporation PERC 3/Si
+	Dell Computer Corporation PERC 3/Di
+	HP NetRAID-4M
+
+Probably Supported Devices
+-------------------------
+	Any and All Adaptec branded AAC964/5400 series raid controllers.
+
+People
+-------------------------
+Alan Cox <alan@redhat.com>
+Christoph Hellwig <hch@caldera.de>	(small cleanups/fixes)
+Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
+
+Original Driver
+-------------------------
+Adaptec Unix OEM Product Group
+
+Mailing List
+-------------------------
+None currently. Also note this is very different to Brian's original driver
+so don't expect him to support it.
+
+Original by Brian Boerner February 2001
+Rewritten by Alan Cox, November 2001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/TODO linux/drivers/scsi/aacraid/TODO
--- linux-2.4.16/drivers/scsi/aacraid/TODO	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/TODO	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,4 @@
+o	Testing
+o	More testing
+o	Feature request: display the firmware/bios/etc revisions in the
+	/proc info
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/aachba.c linux/drivers/scsi/aacraid/aachba.c
--- linux-2.4.16/drivers/scsi/aacraid/aachba.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/aachba.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,1153 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#define MAJOR_NR SCSI_DISK0_MAJOR	/* For DEVICE_NR() */
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+#include "sd.h"
+
+#include "aacraid.h"
+
+/*	SCSI Commands */
+#define	SS_TEST			0x00	/* Test unit ready */
+#define SS_REZERO		0x01	/* Rezero unit */
+#define	SS_REQSEN		0x03	/* Request Sense */
+#define SS_REASGN		0x07	/* Reassign blocks */
+#define	SS_READ			0x08	/* Read 6   */
+#define	SS_WRITE		0x0A	/* Write 6  */
+#define	SS_INQUIR		0x12	/* inquiry */
+#define	SS_ST_SP		0x1B	/* Start/Stop unit */
+#define	SS_LOCK			0x1E	/* prevent/allow medium removal */
+#define SS_RESERV		0x16	/* Reserve */
+#define SS_RELES		0x17	/* Release */
+#define SS_MODESEN		0x1A	/* Mode Sense 6 */
+#define	SS_RDCAP		0x25	/* Read Capacity */
+#define	SM_READ			0x28	/* Read 10  */
+#define	SM_WRITE		0x2A	/* Write 10 */
+#define SS_SEEK			0x2B	/* Seek */
+
+/* values for inqd_pdt: Peripheral device type in plain English */
+#define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
+#define	INQD_PDT_PROC	0x03	/* Processor device */
+#define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
+#define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
+#define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
+#define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
+
+#define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
+#define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
+
+#define	TARGET_LUN_TO_CONTAINER(target, lun)	(((lun) << 4) | target)
+#define CONTAINER_TO_TARGET(cont)		((cont) & 0xf)
+#define CONTAINER_TO_LUN(cont)			((cont) >> 4)
+
+#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER))
+
+#define MAX_DRIVER_SG_SEGMENT_COUNT 17
+
+/*
+ *	Sense keys
+ */
+#define SENKEY_NO_SENSE      0x00	
+#define SENKEY_UNDEFINED     0x01	
+#define SENKEY_NOT_READY     0x02	
+#define SENKEY_MEDIUM_ERR    0x03	
+#define SENKEY_HW_ERR        0x04	
+#define SENKEY_ILLEGAL       0x05	
+#define SENKEY_ATTENTION     0x06	
+#define SENKEY_PROTECTED     0x07	
+#define SENKEY_BLANK         0x08	
+#define SENKEY_V_UNIQUE      0x09	
+#define SENKEY_CPY_ABORT     0x0A	
+#define SENKEY_ABORT         0x0B	
+#define SENKEY_EQUAL         0x0C	
+#define SENKEY_VOL_OVERFLOW  0x0D	
+#define SENKEY_MISCOMP       0x0E	
+#define SENKEY_RESERVED      0x0F	
+
+/*
+ *	Sense codes
+ */
+ 
+#define SENCODE_NO_SENSE                        0x00
+#define SENCODE_END_OF_DATA                     0x00
+#define SENCODE_BECOMING_READY                  0x04
+#define SENCODE_INIT_CMD_REQUIRED               0x04
+#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
+#define SENCODE_INVALID_COMMAND                 0x20
+#define SENCODE_LBA_OUT_OF_RANGE                0x21
+#define SENCODE_INVALID_CDB_FIELD               0x24
+#define SENCODE_LUN_NOT_SUPPORTED               0x25
+#define SENCODE_INVALID_PARAM_FIELD             0x26
+#define SENCODE_PARAM_NOT_SUPPORTED             0x26
+#define SENCODE_PARAM_VALUE_INVALID             0x26
+#define SENCODE_RESET_OCCURRED                  0x29
+#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
+#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
+#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
+#define SENCODE_DIAGNOSTIC_FAILURE              0x40
+#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
+#define SENCODE_INVALID_MESSAGE_ERROR           0x49
+#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
+#define SENCODE_OVERLAPPED_COMMAND              0x4E
+
+/*
+ *	Additional sense codes
+ */
+ 
+#define ASENCODE_NO_SENSE                       0x00
+#define ASENCODE_END_OF_DATA                    0x05
+#define ASENCODE_BECOMING_READY                 0x01
+#define ASENCODE_INIT_CMD_REQUIRED              0x02
+#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
+#define ASENCODE_INVALID_COMMAND                0x00
+#define ASENCODE_LBA_OUT_OF_RANGE               0x00
+#define ASENCODE_INVALID_CDB_FIELD              0x00
+#define ASENCODE_LUN_NOT_SUPPORTED              0x00
+#define ASENCODE_INVALID_PARAM_FIELD            0x00
+#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
+#define ASENCODE_PARAM_VALUE_INVALID            0x02
+#define ASENCODE_RESET_OCCURRED                 0x00
+#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
+#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
+#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
+#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
+#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
+#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
+#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
+#define ASENCODE_OVERLAPPED_COMMAND             0x00
+
+#define BYTE0(x) (unsigned char)(x)
+#define BYTE1(x) (unsigned char)((x) >> 8)
+#define BYTE2(x) (unsigned char)((x) >> 16)
+#define BYTE3(x) (unsigned char)((x) >> 24)
+
+/*------------------------------------------------------------------------------
+ *              S T R U C T S / T Y P E D E F S
+ *----------------------------------------------------------------------------*/
+/* SCSI inquiry data */
+struct inquiry_data {
+	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
+	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
+	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
+	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
+	u8 inqd_len;	/* Additional length (n-4) */
+	u8 inqd_pad1[2];/* Reserved - must be zero */
+	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+	u8 inqd_vid[8];	/* Vendor ID */
+	u8 inqd_pid[16];/* Product ID */
+	u8 inqd_prl[4];	/* Product Revision Level */
+};
+
+struct sense_data {
+	u8 error_code;		/* 70h (current errors), 71h(deferred errors) */
+	u8 valid:1;		/* A valid bit of one indicates that the information  */
+	/* field contains valid information as defined in the
+	 * SCSI-2 Standard.
+	 */
+	u8 segment_number;	/* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */
+	u8 sense_key:4;		/* Sense Key */
+	u8 reserved:1;
+	u8 ILI:1;		/* Incorrect Length Indicator */
+	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
+	u8 filemark:1;		/* Filemark - reserved for random access devices */
+
+	u8 information[4];	/* for direct-access devices, contains the unsigned 
+				 * logical block address or residue associated with 
+				 * the sense key 
+				 */
+	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
+	u8 cmnd_info[4];	/* not used */
+	u8 ASC;			/* Additional Sense Code */
+	u8 ASCQ;		/* Additional Sense Code Qualifier */
+	u8 FRUC;		/* Field Replaceable Unit Code - not used */
+	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
+				 * was in error
+				 */
+	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
+				 * the bit_ptr field has valid value
+				 */
+	u8 reserved2:2;
+	u8 CD:1;		/* command data bit: 1- illegal parameter in CDB.
+				 * 0- illegal parameter in data.
+				 */
+	u8 SKSV:1;
+	u8 field_ptr[2];	/* byte of the CDB or parameter data in error */
+};
+
+/*
+ *              M O D U L E   G L O B A L S
+ */
+ 
+static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS];	/*  SCSI Device Instance Pointers */
+static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS];
+static void get_sd_devname(int disknum, char *buffer);
+
+/**
+ *	aac_get_containers	-	list containers
+ *	@common: adapter to probe
+ *
+ *	Make a list of all containers on this controller
+ */
+int aac_get_containers(struct aac_dev *dev)
+{
+	struct fsa_scsi_hba *fsa_dev_ptr;
+	int index, status = 0;
+	struct aac_query_mount *dinfo;
+	struct aac_mount *dresp;
+	struct fib * fibptr;
+	unsigned instance;
+
+	fsa_dev_ptr = &(dev->fsa_dev);
+	instance = dev->scsi_host_ptr->unique_id;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) {
+		fib_init(fibptr);
+		dinfo = (struct aac_query_mount *) fib_data(fibptr);
+
+		dinfo->command = cpu_to_le32(VM_NameServe);
+		dinfo->count = cpu_to_le32(index);
+		dinfo->type = cpu_to_le32(FT_FILESYS);
+
+		status = fib_send(ContainerCommand,
+				    fibptr,
+				    sizeof (struct aac_query_mount),
+				    FsaNormal,
+				    1, 1,
+				    NULL, NULL);
+		if (status < 0 ) {
+			printk(KERN_WARNING "ProbeContainers: SendFIB failed.\n");
+			break;
+		}
+		dresp = (struct aac_mount *)fib_data(fibptr);
+
+		if ((le32_to_cpu(dresp->status) == ST_OK) &&
+		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
+			fsa_dev_ptr->valid[index] = 1;
+			fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol);
+			fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity);
+			if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
+				    fsa_dev_ptr->ro[index] = 1;
+		}
+		fib_complete(fibptr);
+		/*
+		 *	If there are no more containers, then stop asking.
+		 */
+		if ((index + 1) >= le32_to_cpu(dresp->count))
+			break;
+	}
+	fib_free(fibptr);
+	fsa_dev[instance] = fsa_dev_ptr;
+	return status;
+}
+
+/**
+ *	probe_container		-	query a logical volume
+ *	@dev: device to query
+ *	@cid: container identifier
+ *
+ *	Queries the controller about the given volume. The volume information
+ *	is updated in the struct fsa_scsi_hba structure rather than returned.
+ */
+ 
+static int probe_container(struct aac_dev *dev, int cid)
+{
+	struct fsa_scsi_hba *fsa_dev_ptr;
+	int status;
+	struct aac_query_mount *dinfo;
+	struct aac_mount *dresp;
+	struct fib * fibptr;
+	unsigned instance;
+
+	fsa_dev_ptr = &(dev->fsa_dev);
+	instance = dev->scsi_host_ptr->unique_id;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+
+	dinfo = (struct aac_query_mount *)fib_data(fibptr);
+
+	dinfo->command = cpu_to_le32(VM_NameServe);
+	dinfo->count = cpu_to_le32(cid);
+	dinfo->type = cpu_to_le32(FT_FILESYS);
+
+	status = fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof(struct aac_query_mount),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL);
+	if (status < 0) {
+		printk(KERN_WARNING "aacraid: probe_containers query failed.\n");
+		goto error;
+	}
+
+	dresp = (struct aac_mount *) fib_data(fibptr);
+
+	if ((le32_to_cpu(dresp->status) == ST_OK) &&
+	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
+		fsa_dev_ptr->valid[cid] = 1;
+		fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol);
+		fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity);
+		if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
+			fsa_dev_ptr->ro[cid] = 1;
+	}
+
+error:
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
+	return status;
+}
+
+/* Local Structure to set SCSI inquiry data strings */
+struct scsi_inq {
+	char vid[8];         /* Vendor ID */
+	char pid[16];        /* Product ID */
+	char prl[4];         /* Product Revision Level */
+};
+
+/**
+ *	InqStrCopy	-	string merge
+ *	@a:	string to copy from
+ *	@b:	string to copy to
+ *
+ * 	Copy a String from one location to another
+ *	without copying \0
+ */
+
+static void inqstrcpy(char *a, char *b)
+{
+
+	while(*a != (char)0) 
+		*b++ = *a++;
+}
+
+static char *container_types[] = {
+        "None",
+        "Volume",
+        "Mirror",
+        "Stripe",
+        "RAID5",
+        "SSRW",
+        "SSRO",
+        "Morph",
+        "Legacy",
+        "RAID4",
+        "RAID10",             
+        "RAID00",             
+        "V-MIRRORS",          
+        "PSEUDO R4",          
+	"RAID50",
+        "Unknown"
+};
+
+
+
+/* Function: setinqstr
+ *
+ * Arguments: [1] pointer to void [1] int
+ *
+ * Purpose: Sets SCSI inquiry data strings for vendor, product
+ * and revision level. Allows strings to be set in platform dependant
+ * files instead of in OS dependant driver source.
+ */
+
+static void setinqstr(int devtype, void *data, int tindex)
+{
+	struct scsi_inq *str;
+	char *findit;
+	struct aac_driver_ident *mp;
+	extern struct aac_driver_ident aac_drivers[];	/* HACK FIXME */
+
+	mp = &aac_drivers[devtype];
+   
+	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
+
+	inqstrcpy (mp->vname, str->vid); 
+	inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */
+
+	findit = str->pid;
+
+	for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */
+		findit++;
+	
+	if (tindex < (sizeof(container_types)/sizeof(char *))){
+		inqstrcpy (container_types[tindex], findit);
+	}
+	inqstrcpy ("0001", str->prl);
+}
+
+void set_sense(char *sense_buf, u8 sense_key, u8 sense_code,
+		    u8 a_sense_code, u8 incorrect_length,
+		    u8 bit_pointer, unsigned field_pointer,
+		    unsigned long residue)
+{
+	sense_buf[0] = 0xF0;	/* Sense data valid, err code 70h (current error) */
+	sense_buf[1] = 0;	/* Segment number, always zero */
+
+	if (incorrect_length) {
+		sense_buf[2] = sense_key | 0x20;	/* Set the ILI bit | sense key */
+		sense_buf[3] = BYTE3(residue);
+		sense_buf[4] = BYTE2(residue);
+		sense_buf[5] = BYTE1(residue);
+		sense_buf[6] = BYTE0(residue);
+	} else
+		sense_buf[2] = sense_key;	/* Sense key */
+
+	if (sense_key == SENKEY_ILLEGAL)
+		sense_buf[7] = 10;	/* Additional sense length */
+	else
+		sense_buf[7] = 6;	/* Additional sense length */
+
+	sense_buf[12] = sense_code;	/* Additional sense code */
+	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */
+	if (sense_key == SENKEY_ILLEGAL) {
+		sense_buf[15] = 0;
+
+		if (sense_code == SENCODE_INVALID_PARAM_FIELD)
+			sense_buf[15] = 0x80;	/* Std sense key specific field */
+		/* Illegal parameter is in the parameter block */
+
+		if (sense_code == SENCODE_INVALID_CDB_FIELD)
+			sense_buf[15] = 0xc0;	/* Std sense key specific field */
+		/* Illegal parameter is in the CDB block */
+		sense_buf[15] |= bit_pointer;
+		sense_buf[16] = field_pointer >> 8;	/* MSB */
+		sense_buf[17] = field_pointer;		/* LSB */
+	}
+}
+
+static void aac_io_done(Scsi_Cmnd * scsicmd)
+{
+	unsigned long cpu_flags;
+	spin_lock_irqsave(&io_request_lock, cpu_flags);
+	scsicmd->scsi_done(scsicmd);
+	spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+}
+
+static void __aac_io_done(Scsi_Cmnd * scsicmd)
+{
+	scsicmd->scsi_done(scsicmd);
+}
+
+static void read_callback(void *context, struct fib * fibptr)
+{
+	struct aac_dev *dev;
+	struct aac_read_reply *readreply;
+	Scsi_Cmnd *scsicmd;
+	unsigned long lba;
+	int cid;
+
+	scsicmd = (Scsi_Cmnd *) context;
+
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	cid =TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
+
+	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies));
+
+	if (fibptr == NULL)
+		BUG();
+		
+	if(scsicmd->use_sg)
+		pci_unmap_sg(dev->pdev, 
+			(struct scatterlist *)scsicmd->buffer,
+			scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+	else if(scsicmd->request_bufflen)
+		pci_unmap_single(dev->pdev, (u32)scsicmd->SCp.ptr, scsicmd->request_bufflen,
+				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+	readreply = (struct aac_read_reply *)fib_data(fibptr);
+	if (le32_to_cpu(readreply->status) == ST_OK)
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+	else {
+		printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status);
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		set_sense((char *) &sense_data[cid],
+				    SENKEY_HW_ERR,
+				    SENCODE_INTERNAL_TARGET_FAILURE,
+				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+				    0, 0);
+	}
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
+	aac_io_done(scsicmd);
+}
+
+static void write_callback(void *context, struct fib * fibptr)
+{
+	struct aac_dev *dev;
+	struct aac_write_reply *writereply;
+	Scsi_Cmnd *scsicmd;
+	unsigned long lba;
+	int cid;
+
+	scsicmd = (Scsi_Cmnd *) context;
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
+
+	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	if (fibptr == NULL)
+		BUG();
+
+	if(scsicmd->use_sg)
+		pci_unmap_sg(dev->pdev, 
+			(struct scatterlist *)scsicmd->buffer,
+			scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+	else if(scsicmd->request_bufflen)
+		pci_unmap_single(dev->pdev, (u32)scsicmd->SCp.ptr, scsicmd->request_bufflen,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+
+	writereply = (struct aac_write_reply *) fib_data(fibptr);
+	if (le32_to_cpu(writereply->status) == ST_OK)
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+	else {
+		printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		set_sense((char *) &sense_data[cid],
+				    SENKEY_HW_ERR,
+				    SENCODE_INTERNAL_TARGET_FAILURE,
+				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+				    0, 0);
+	}
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(scsicmd);
+}
+
+int aac_read(Scsi_Cmnd * scsicmd, int cid)
+{
+	unsigned long lba;
+	unsigned long count;
+	unsigned long byte_count = 0;
+	int status;
+
+	struct aac_read *readcmd;
+	u16 fibsize;
+	struct aac_dev *dev;
+	struct fib * cmd_fibcontext;
+
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	/*
+	 *	Get block address and transfer length
+	 */
+	if (scsicmd->cmnd[0] == SS_READ)	/* 6 byte command */
+	{
+		dprintk((KERN_DEBUG "aachba: received a read(6) command on target %d.\n", cid));
+
+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+		count = scsicmd->cmnd[4];
+
+		if (count == 0)
+			count = 256;
+	} else {
+		dprintk((KERN_DEBUG "aachba: received a read(10) command on target %d.\n", cid));
+
+		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+	}
+	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	/*
+	 *	Alocate and initialize a Fib
+	 */
+	if (!(cmd_fibcontext = fib_alloc(dev))) {
+		scsicmd->result = DID_ERROR << 16;
+		aac_io_done(scsicmd);
+		return (-1);
+	}
+
+	fib_init(cmd_fibcontext);
+
+	readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
+	readcmd->command = cpu_to_le32(VM_CtBlockRead);
+	readcmd->cid = cpu_to_le32(cid);
+	readcmd->block = cpu_to_le32(lba);
+	readcmd->count = cpu_to_le32(count * 512);
+	readcmd->sg.count = cpu_to_le32(1);
+
+	if (count * 512 > (64 * 1024))
+		BUG();
+	/*
+	 *	Build Scatter/Gather list
+	 */
+	if (scsicmd->use_sg)	/* use scatter/gather list */
+	{
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+
+		sg = (struct scatterlist *) scsicmd->request_buffer;
+		
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+			
+		byte_count = 0;
+
+		for (i = 0; i < sg_count; i++) {
+			readcmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg));
+			readcmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg));
+			byte_count += sg->length;
+			if (sg->length > (64 * 1024))
+				BUG();
+			sg++;
+		}
+		readcmd->sg.count = cpu_to_le32(sg_count);
+
+		if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT)
+			BUG();
+	}
+	else if(scsicmd->request_bufflen)
+	{
+		u32 addr;
+		addr = pci_map_single(dev->pdev, scsicmd->request_buffer,
+				scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		scsicmd->SCp.ptr = (void *)addr;
+		readcmd->sg.sg[0].addr = cpu_to_le32(addr);
+		readcmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
+
+		byte_count = scsicmd->request_bufflen;
+
+		if (byte_count > (64 * 1024))
+			BUG();
+	}
+	if (byte_count != readcmd->count)
+		BUG();
+	/*
+	 *	Now send the Fib to the adapter
+	 */
+	fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry));
+	status = fib_send(ContainerCommand, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) read_callback, 
+			  (void *) scsicmd);
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) 
+		return 0;
+		
+	printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status);
+	/*
+	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
+	 */
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL;
+	aac_io_done(scsicmd);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return -1;
+}
+
+static int aac_write(Scsi_Cmnd * scsicmd, int cid)
+{
+	unsigned long lba;
+	unsigned long count;
+	unsigned long byte_count = 0;
+	int status;
+	struct aac_write *writecmd;
+	u16 fibsize;
+	struct aac_dev *dev;
+	struct fib * cmd_fibcontext;
+
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	/*
+	 *	Get block address and transfer length
+	 */
+	if (scsicmd->cmnd[0] == SS_WRITE)	/* 6 byte command */
+	{
+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+		count = scsicmd->cmnd[4];
+		if (count == 0)
+			count = 256;
+	} else {
+		dprintk((KERN_DEBUG "aachba: received a write(10) command on target %d.\n", cid));
+		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+	}
+	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(cmd_fibcontext = fib_alloc(dev))) {
+		scsicmd->result = DID_ERROR << 16;
+		aac_io_done(scsicmd);
+		return -1;
+	}
+	fib_init(cmd_fibcontext);
+
+	writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
+	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
+	writecmd->cid = cpu_to_le32(cid);
+	writecmd->block = cpu_to_le32(lba);
+	writecmd->count = cpu_to_le32(count * 512);
+	writecmd->sg.count = cpu_to_le32(1);
+	/* FIXME: why isnt ->stable setup */
+
+	if (count * 512 > (64 * 1024)) {
+		BUG();
+	}
+	/*
+	 *	Build Scatter/Gather list
+	 */
+	if (scsicmd->use_sg)
+	{
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+		
+		sg = (struct scatterlist *) scsicmd->request_buffer;
+
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+
+		byte_count = 0;
+
+		for (i = 0; i < scsicmd->use_sg; i++) {
+			writecmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg));
+			writecmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg));
+			byte_count += sg->length;
+
+			if (sg->length > (64 * 1024))
+				BUG();
+			sg++;
+		}
+		writecmd->sg.count = cpu_to_le32(sg_count);
+
+		if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT)
+			BUG();
+	}
+	else if(scsicmd->request_bufflen)
+	{
+		u32 addr; 
+		addr = pci_map_single(dev->pdev,
+				scsicmd->request_buffer,
+				scsicmd->request_bufflen,
+				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		writecmd->sg.sg[0].addr = cpu_to_le32(addr);
+		writecmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
+		scsicmd->SCp.ptr = (void *)addr;
+		byte_count = scsicmd->request_bufflen;
+
+		if (byte_count > (64 * 1024))
+			BUG();
+	}
+	if (byte_count != writecmd->count)
+		BUG();
+	/*
+	 *	Now send the Fib to the adapter
+	 */
+	fibsize = sizeof (struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry));
+
+	status = fib_send(ContainerCommand, 
+			  cmd_fibcontext,
+			  fibsize, FsaNormal,
+			  0, 1,
+			  (fib_callback) write_callback,
+			  (void *) scsicmd);
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS)
+		return 0;
+
+	printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status);
+	/*
+	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
+	 */
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL;
+	aac_io_done(scsicmd);
+
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return -1;
+}
+
+
+/**
+ *	aac_scsi_cmd()		-	Process SCSI command
+ *	@scsicmd:		SCSI command block
+ *	@wait:			1 if the user wants to await completion
+ *
+ *	Emulate a SCSI command and queue the required request for the
+ *	aacraid firmware.
+ */
+ 
+int aac_scsi_cmd(Scsi_Cmnd * scsicmd)
+{
+	int cid = 0;
+	struct fsa_scsi_hba *fsa_dev_ptr;
+	int cardtype;
+	int ret;
+	struct aac_dev *dev = (struct aac_dev *)scsicmd->host->hostdata;
+	
+	cardtype = dev->cardtype;
+
+	fsa_dev_ptr = fsa_dev[scsicmd->host->unique_id];
+
+	/*
+	 *	If the bus, target or lun is out of range, return fail
+	 *	Test does not apply to ID 16, the pseudo id for the controller
+	 *	itself.
+	 */
+	if (scsicmd->target != scsicmd->host->this_id) {
+		if ((scsicmd->channel > 0) ||(scsicmd->target > 15) || (scsicmd->lun > 7)) 
+		{
+			dprintk((KERN_DEBUG "The bus, target or lun is out of range = %d, %d, %d.\n", 
+				scsicmd->channel, scsicmd->target, scsicmd->lun));
+			scsicmd->result = DID_BAD_TARGET << 16;
+			__aac_io_done(scsicmd);
+			return -1;
+		}
+		cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
+		/*
+		 *	If the target container doesn't exist, it may have
+		 *	been newly created
+		 */
+		if (fsa_dev_ptr->valid[cid] == 0) {
+			switch (scsicmd->cmnd[0]) {
+			case SS_INQUIR:
+			case SS_RDCAP:
+			case SS_TEST:
+				spin_unlock_irq(&io_request_lock);
+				probe_container(dev, cid);
+				spin_lock_irq(&io_request_lock);
+			default:
+				break;
+			}
+		}
+		/*
+		 *	If the target container still doesn't exist, 
+		 *	return failure
+		 */
+		if (fsa_dev_ptr->valid[cid] == 0) {
+			scsicmd->result = DID_BAD_TARGET << 16;
+			__aac_io_done(scsicmd);
+			return -1;
+		}
+	} 
+	else if ((scsicmd->cmnd[0] != SS_INQUIR) &&	/* only INQUIRY & TUR cmnd supported for controller */
+	    (scsicmd->cmnd[0] != SS_TEST)) 
+	{
+		/*
+		 *	Command aimed at the controller
+		 */
+		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		set_sense((char *) &sense_data[cid],
+			    SENKEY_ILLEGAL,
+			    SENCODE_INVALID_COMMAND,
+			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+		__aac_io_done(scsicmd);
+		return -1;
+	}
+	/* Handle commands here that don't really require going out to the adapter */
+	switch (scsicmd->cmnd[0]) 
+	{
+		case SS_INQUIR:
+		{
+			struct inquiry_data *inq_data_ptr;
+
+			dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target));
+			inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
+			memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
+
+			inq_data_ptr->inqd_ver = 2;	/* claim compliance to SCSI-2 */
+			inq_data_ptr->inqd_dtq = 0x80;	/* set RMB bit to one indicating that the medium is removable */
+			inq_data_ptr->inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
+			inq_data_ptr->inqd_len = 31;
+
+			/*
+			 *	Set the Vendor, Product, and Revision Level
+			 *	see: <vendor>.c i.e. aac.c
+			 */
+			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
+			if (scsicmd->target == scsicmd->host->this_id)
+			    	inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
+			else
+				inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			__aac_io_done(scsicmd);
+			return 0;
+		}
+		case SS_RDCAP:
+		{
+			int capacity;
+			char *cp;
+
+			dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
+			capacity = fsa_dev_ptr->size[cid] - 1;
+			cp = scsicmd->request_buffer;
+			cp[0] = (capacity >> 24) & 0xff;
+			cp[1] = (capacity >> 16) & 0xff;
+			cp[2] = (capacity >> 8) & 0xff;
+			cp[3] = (capacity >> 0) & 0xff;
+			cp[4] = 0;
+			cp[5] = 0;
+			cp[6] = 2;
+			cp[7] = 0;
+
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			__aac_io_done(scsicmd);
+
+			return 0;
+		}
+
+		case SS_MODESEN:
+		{
+			char *mode_buf;
+
+			dprintk((KERN_DEBUG "MODE SENSE command.\n"));
+			mode_buf = scsicmd->request_buffer;
+			mode_buf[0] = 0;	/* Mode data length (MSB) */
+			mode_buf[1] = 6;	/* Mode data length (LSB) */
+			mode_buf[2] = 0;	/* Medium type - default */
+			mode_buf[3] = 0;	/* Device-specific param, bit 8: 0/1 = write enabled/protected */
+			mode_buf[4] = 0;	/* reserved */
+			mode_buf[5] = 0;	/* reserved */
+			mode_buf[6] = 0;	/* Block descriptor length (MSB) */
+			mode_buf[7] = 0;	/* Block descriptor length (LSB) */
+
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			__aac_io_done(scsicmd);
+
+			return 0;
+		}
+		case SS_REQSEN:
+			dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
+			memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data));
+			memset(&sense_data[cid], 0, sizeof (struct sense_data));
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			__aac_io_done(scsicmd);
+			return (0);
+
+		case SS_LOCK:
+			dprintk((KERN_DEBUG "LOCK command.\n"));
+			if (scsicmd->cmnd[4])
+				fsa_dev_ptr->locked[cid] = 1;
+			else
+				fsa_dev_ptr->locked[cid] = 0;
+
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			__aac_io_done(scsicmd);
+			return 0;
+		/*
+		 *	These commands are all No-Ops
+		 */
+		case SS_TEST:
+		case SS_RESERV:
+		case SS_RELES:
+		case SS_REZERO:
+		case SS_REASGN:
+		case SS_SEEK:
+		case SS_ST_SP:
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			__aac_io_done(scsicmd);
+			return (0);
+	}
+
+	switch (scsicmd->cmnd[0]) 
+	{
+		case SS_READ:
+		case SM_READ:
+			/*
+			 *	Hack to keep track of ordinal number of the device that
+			 *	corresponds to a container. Needed to convert
+			 *	containers to /dev/sd device names
+			 */
+			 
+			spin_unlock_irq(&io_request_lock);
+			fsa_dev_ptr->devno[cid] = DEVICE_NR(scsicmd->request.rq_dev);
+			ret = aac_read(scsicmd, cid);
+			spin_lock_irq(&io_request_lock);
+			return ret;
+
+		case SS_WRITE:
+		case SM_WRITE:
+			spin_unlock_irq(&io_request_lock);
+			ret = aac_write(scsicmd, cid);
+			spin_lock_irq(&io_request_lock);
+			return ret;
+		default:
+			/*
+			 *	Unhandled commands
+			 */
+			printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]);
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+			set_sense((char *) &sense_data[cid],
+				SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND,
+			ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+			__aac_io_done(scsicmd);
+			return -1;
+	}
+}
+
+static int query_disk(struct aac_dev *dev, void *arg)
+{
+	struct aac_query_disk qd;
+	struct fsa_scsi_hba *fsa_dev_ptr;
+
+	fsa_dev_ptr = &(dev->fsa_dev);
+	if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
+		return -EFAULT;
+	if (qd.cnum == -1)
+		qd.cnum = TARGET_LUN_TO_CONTAINER(qd.target, qd.lun);
+	else if ((qd.bus == -1) && (qd.target == -1) && (qd.lun == -1)) 
+	{
+		if (qd.cnum < 0 || qd.cnum > MAXIMUM_NUM_CONTAINERS)
+			return -EINVAL;
+		qd.instance = dev->scsi_host_ptr->host_no;
+		qd.bus = 0;
+		qd.target = CONTAINER_TO_TARGET(qd.cnum);
+		qd.lun = CONTAINER_TO_LUN(qd.cnum);
+	}
+	else return -EINVAL;
+
+	qd.valid = fsa_dev_ptr->valid[qd.cnum];
+	qd.locked = fsa_dev_ptr->locked[qd.cnum];
+	qd.deleted = fsa_dev_ptr->deleted[qd.cnum];
+
+	if (fsa_dev_ptr->devno[qd.cnum] == -1)
+		qd.unmapped = 1;
+	else
+		qd.unmapped = 0;
+
+	get_sd_devname(fsa_dev_ptr->devno[qd.cnum], qd.name);
+
+	if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
+		return -EFAULT;
+	return 0;
+}
+
+static void get_sd_devname(int disknum, char *buffer)
+{
+	if (disknum < 0) {
+		sprintf(buffer, "%s", "");
+		return;
+	}
+
+	if (disknum < 26)
+		sprintf(buffer, "sd%c", 'a' + disknum);
+	else {
+		unsigned int min1;
+		unsigned int min2;
+		/*
+		 * For larger numbers of disks, we need to go to a new
+		 * naming scheme.
+		 */
+		min1 = disknum / 26;
+		min2 = disknum % 26;
+		sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
+	}
+}
+
+static int force_delete_disk(struct aac_dev *dev, void *arg)
+{
+	struct aac_delete_disk dd;
+	struct fsa_scsi_hba *fsa_dev_ptr;
+
+	fsa_dev_ptr = &(dev->fsa_dev);
+
+	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
+		return -EFAULT;
+
+	if (dd.cnum > MAXIMUM_NUM_CONTAINERS)
+		return -EINVAL;
+	/*
+	 *	Mark this container as being deleted.
+	 */
+	fsa_dev_ptr->deleted[dd.cnum] = 1;
+	/*
+	 *	Mark the container as no longer valid
+	 */
+	fsa_dev_ptr->valid[dd.cnum] = 0;
+	return 0;
+}
+
+static int delete_disk(struct aac_dev *dev, void *arg)
+{
+	struct aac_delete_disk dd;
+	struct fsa_scsi_hba *fsa_dev_ptr;
+
+	fsa_dev_ptr = &(dev->fsa_dev);
+
+	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
+		return -EFAULT;
+
+	if (dd.cnum > MAXIMUM_NUM_CONTAINERS)
+		return -EINVAL;
+	/*
+	 *	If the container is locked, it can not be deleted by the API.
+	 */
+	if (fsa_dev_ptr->locked[dd.cnum])
+		return -EBUSY;
+	else {
+		/*
+		 *	Mark the container as no longer being valid.
+		 */
+		fsa_dev_ptr->valid[dd.cnum] = 0;
+		fsa_dev_ptr->devno[dd.cnum] = -1;
+		return 0;
+	}
+}
+
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg)
+{
+	switch (cmd) {
+	case FSACTL_QUERY_DISK:
+		return query_disk(dev, arg);
+	case FSACTL_DELETE_DISK:
+		return delete_disk(dev, arg);
+	case FSACTL_FORCE_DELETE_DISK:
+		return force_delete_disk(dev, arg);
+	case 2131:
+		return aac_get_containers(dev);
+	default:
+		return -ENOTTY;
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/aacraid.h linux/drivers/scsi/aacraid/aacraid.h
--- linux-2.4.16/drivers/scsi/aacraid/aacraid.h	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/aacraid.h	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,1198 @@
+#define dprintk(x)	printk x
+
+#define AAC_NUM_FIB	128
+#define AAC_NUM_IO_FIB	116
+
+/*------------------------------------------------------------------------------
+ *              D E F I N E S
+ *----------------------------------------------------------------------------*/
+
+struct diskparm
+{
+	int heads;
+	int sectors;
+	int cylinders;
+};
+
+
+/*
+ *	DON'T CHANGE THE ORDER, this is set by the firmware
+ */
+ 
+#define		CT_NONE			0
+#define		CT_VOLUME		1
+#define		CT_MIRROR		2
+#define		CT_STRIPE		3
+#define		CT_RAID5		4
+#define		CT_SSRW			5
+#define		CT_SSRO			6
+#define		CT_MORPH		7
+#define		CT_PASSTHRU		8
+#define		CT_RAID4		9
+#define		CT_RAID10		10	/* stripe of mirror */
+#define		CT_RAID00		11	/* stripe of stripe */
+#define		CT_VOLUME_OF_MIRRORS	12	/* volume of mirror */
+#define		CT_PSEUDO_RAID		13	/* really raid4 */
+#define		CT_LAST_VOLUME_TYPE	14
+
+/*
+ *	Types of objects addressable in some fashion by the client.
+ *	This is a superset of those objects handled just by the filesystem
+ *	and includes "raw" objects that an administrator would use to
+ *	configure containers and filesystems.
+ */
+
+#define		FT_REG		1	/* regular file */
+#define		FT_DIR		2	/* directory */
+#define		FT_BLK		3	/* "block" device - reserved */
+#define		FT_CHR		4	/* "character special" device - reserved */
+#define		FT_LNK		5	/* symbolic link */
+#define		FT_SOCK		6	/* socket */
+#define		FT_FIFO		7	/* fifo */
+#define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
+#define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/target/lun */
+#define		FT_SLICE	10	/* virtual disk - raw volume - slice */
+#define		FT_PARTITION	11	/* FSA partition - carved out of a slice - building block for containers */
+#define		FT_VOLUME	12	/* Container - Volume Set */
+#define		FT_STRIPE	13	/* Container - Stripe Set */
+#define		FT_MIRROR	14	/* Container - Mirror Set */
+#define		FT_RAID5	15	/* Container - Raid 5 Set */
+#define		FT_DATABASE	16	/* Storage object with "foreign" content manager */
+
+/*
+ *	Host side memory scatter gather list
+ *	Used by the adapter for read, write, and readdirplus operations
+ */
+
+struct sgentry {
+	u32	addr;	/* 32-bit Base address. */
+	u32	count;	/* Length. */
+};
+
+/*
+ *	SGMAP
+ *
+ *	This is the SGMAP structure for all commands that use
+ *	32-bit addressing.
+ *
+ *	Note that the upper 16 bits of SgCount are used as flags.
+ *	Only the lower 16 bits of SgCount are actually used as the
+ *	SG element count.
+ */
+
+struct sgmap {
+	u32		count;
+	struct sgentry	sg[1];
+};
+
+struct creation_info
+{
+	u8 		buildnum;		/* e.g., 588 */
+	u8 		usec;			/* e.g., 588 */
+	u8	 	via;			/* e.g., 1 = FSU,
+						 * 	 2 = API
+						 */
+	u8	 	year;		 	/* e.g., 1997 = 97 */
+	u32		date;			/*
+						 * unsigned 	Month		:4;	// 1 - 12
+						 * unsigned 	Day		:6;	// 1 - 32
+						 * unsigned 	Hour		:6;	// 0 - 23
+						 * unsigned 	Minute		:6;	// 0 - 60
+						 * unsigned 	Second		:6;	// 0 - 60
+						 */
+	u64		serial;			/* e.g., 0x1DEADB0BFAFAF001 */
+};
+
+
+/*
+ *	Define all the constants needed for the communication interface
+ */
+
+/*
+ *	Define how many queue entries each queue will have and the total
+ *	number of entries for the entire communication interface. Also define
+ *	how many queues we support.
+ *
+ *	This has to match the controller
+ */
+
+#define NUMBER_OF_COMM_QUEUES  8   // 4 command; 4 response
+#define HOST_HIGH_CMD_ENTRIES  4
+#define HOST_NORM_CMD_ENTRIES  8
+#define ADAP_HIGH_CMD_ENTRIES  4
+#define ADAP_NORM_CMD_ENTRIES  512
+#define HOST_HIGH_RESP_ENTRIES 4
+#define HOST_NORM_RESP_ENTRIES 512
+#define ADAP_HIGH_RESP_ENTRIES 4
+#define ADAP_NORM_RESP_ENTRIES 8
+
+#define TOTAL_QUEUE_ENTRIES  \
+    (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \
+	    HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES)
+
+
+/*
+ *	Set the queues on a 16 byte alignment
+ */
+ 
+#define QUEUE_ALIGNMENT		16
+
+/*
+ *	The queue headers define the Communication Region queues. These
+ *	are physically contiguous and accessible by both the adapter and the
+ *	host. Even though all queue headers are in the same contiguous block
+ *	they will be represented as individual units in the data structures.
+ */
+
+struct aac_entry {
+	u32 size;       /* Size in bytes of the Fib which this QE points to */
+	u32 addr;	/* Receiver addressable address of the FIB (low 32 address bits) */
+};
+
+/*
+ *	The adapter assumes the ProducerIndex and ConsumerIndex are grouped
+ *	adjacently and in that order.
+ */
+ 
+struct aac_qhdr {
+	u64 header_addr;		/* Address to hand the adapter to access to this queue head */
+	u32 *producer;			/* The producer index for this queue (host address) */
+	u32 *consumer;			/* The consumer index for this queue (host address) */
+};
+
+/*
+ *	Define all the events which the adapter would like to notify
+ *	the host of.
+ */
+ 
+#define		HostNormCmdQue		1	/* Change in host normal priority command queue */
+#define		HostHighCmdQue		2	/* Change in host high priority command queue */
+#define		HostNormRespQue		3	/* Change in host normal priority response queue */
+#define		HostHighRespQue		4	/* Change in host high priority response queue */
+#define		AdapNormRespNotFull	5
+#define		AdapHighRespNotFull	6
+#define		AdapNormCmdNotFull	7
+#define		AdapHighCmdNotFull	8
+#define		SynchCommandComplete	9
+#define		AdapInternalError	0xfe    /* The adapter detected an internal error shutting down */
+
+/*
+ *	Define all the events the host wishes to notify the
+ *	adapter of. The first four values much match the Qid the
+ *	corresponding queue.
+ */
+
+#define		AdapNormCmdQue		2
+#define		AdapHighCmdQue		3
+#define		AdapNormRespQue		6
+#define		AdapHighRespQue		7
+#define		HostShutdown		8
+#define		HostPowerFail		9
+#define		FatalCommError		10
+#define		HostNormRespNotFull	11
+#define		HostHighRespNotFull	12
+#define		HostNormCmdNotFull	13
+#define		HostHighCmdNotFull	14
+#define		FastIo			15
+#define		AdapPrintfDone		16
+
+/*
+ *	Define all the queues that the adapter and host use to communicate
+ *	Number them to match the physical queue layout.
+ */
+
+enum aac_queue_types {
+        HostNormCmdQueue = 0,	/* Adapter to host normal priority command traffic */
+        HostHighCmdQueue,	/* Adapter to host high priority command traffic */
+        AdapNormCmdQueue,	/* Host to adapter normal priority command traffic */
+        AdapHighCmdQueue,	/* Host to adapter high priority command traffic */
+        HostNormRespQueue,	/* Adapter to host normal priority response traffic */
+        HostHighRespQueue,	/* Adapter to host high priority response traffic */
+        AdapNormRespQueue,	/* Host to adapter normal priority response traffic */
+        AdapHighRespQueue	/* Host to adapter high priority response traffic */
+};
+
+/*
+ *	Assign type values to the FSA communication data structures
+ */
+
+#define		FIB_MAGIC	0x0001
+
+/*
+ *	Define the priority levels the FSA communication routines support.
+ */
+
+#define		FsaNormal	1
+#define		FsaHigh		2
+
+//
+// Define the FIB. The FIB is the where all the requested data and
+// command information are put to the application on the FSA adapter.
+//
+
+struct aac_fibhdr {
+	u32 XferState;			// Current transfer state for this CCB
+	u16 Command;			// Routing information for the destination
+	u8 StructType;			// Type FIB
+	u8 Flags;			// Flags for FIB
+	u16 Size;			// Size of this FIB in bytes
+	u16 SenderSize;			// Size of the FIB in the sender (for response sizing)
+	u32 SenderFibAddress;		// Host defined data in the FIB
+	u32 ReceiverFibAddress;		// Logical address of this FIB for the adapter
+	u32 SenderData;			// Place holder for the sender to store data
+	union {
+		struct {
+		    u32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
+		    u32 _ReceiverTimeDone;	// Timestamp for completion of fib
+		} _s;
+		struct list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
+	} _u;
+};
+
+#define FibLinks			_u._FibLinks
+
+#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr))
+
+
+struct hw_fib {
+	struct aac_fibhdr header;
+	u8 data[FIB_DATA_SIZE_IN_BYTES];		// Command specific data
+};
+
+/*
+ *	FIB commands
+ */
+
+#define 	TestCommandResponse		1
+#define		TestAdapterCommand		2
+/*
+ *	Lowlevel and comm commands
+ */
+#define		LastTestCommand			100
+#define		ReinitHostNormCommandQueue	101
+#define		ReinitHostHighCommandQueue	102
+#define		ReinitHostHighRespQueue		103
+#define		ReinitHostNormRespQueue		104
+#define		ReinitAdapNormCommandQueue	105
+#define		ReinitAdapHighCommandQueue	107
+#define		ReinitAdapHighRespQueue		108
+#define		ReinitAdapNormRespQueue		109
+#define		InterfaceShutdown		110
+#define		DmaCommandFib			120
+#define		StartProfile			121
+#define		TermProfile			122
+#define		SpeedTest			123
+#define		TakeABreakPt			124
+#define		RequestPerfData			125
+#define		SetInterruptDefTimer		126
+#define		SetInterruptDefCount		127
+#define		GetInterruptDefStatus		128
+#define		LastCommCommand			129
+/*
+ *	Filesystem commands
+ */
+#define		NuFileSystem			300
+#define		UFS				301
+#define		HostFileSystem			302
+#define		LastFileSystemCommand		303
+/*
+ *	Container Commands
+ */
+#define		ContainerCommand		500
+#define		ContainerCommand64		501
+/*
+ *	Cluster Commands
+ */
+#define		ClusterCommand	 		550
+/*
+ *	Scsi Port commands (scsi passthrough)
+ */
+#define		ScsiPortCommand			600
+/*
+ *	Misc house keeping and generic adapter initiated commands
+ */
+#define		AifRequest			700
+#define		CheckRevision			701
+#define		FsaHostShutdown			702
+#define		RequestAdapterInfo		703
+#define		IsAdapterPaused			704
+#define		SendHostTime			705
+#define		LastMiscCommand			706
+
+//
+// Commands that will target the failover level on the FSA adapter
+//
+
+enum fib_xfer_state {
+	HostOwned 			= (1<<0),
+	AdapterOwned 			= (1<<1),
+	FibInitialized 			= (1<<2),
+	FibEmpty 			= (1<<3),
+	AllocatedFromPool 		= (1<<4),
+	SentFromHost 			= (1<<5),
+	SentFromAdapter 		= (1<<6),
+	ResponseExpected 		= (1<<7),
+	NoResponseExpected 		= (1<<8),
+	AdapterProcessed 		= (1<<9),
+	HostProcessed 			= (1<<10),
+	HighPriority 			= (1<<11),
+	NormalPriority 			= (1<<12),
+	Async				= (1<<13),
+	AsyncIo				= (1<<13),	// rpbfix: remove with new regime
+	PageFileIo			= (1<<14),	// rpbfix: remove with new regime
+	ShutdownRequest			= (1<<15),
+	LazyWrite			= (1<<16),	// rpbfix: remove with new regime
+	AdapterMicroFib			= (1<<17),
+	BIOSFibPath			= (1<<18),
+	FastResponseCapable		= (1<<19),
+	ApiFib				= (1<<20)	// Its an API Fib.
+};
+
+/*
+ *	The following defines needs to be updated any time there is an
+ *	incompatible change made to the aac_init structure.
+ */
+
+#define ADAPTER_INIT_STRUCT_REVISION		3
+
+struct aac_init
+{
+	u32	InitStructRevision;
+	u32	MiniPortRevision;
+	u32	fsrev;
+	u32	CommHeaderAddress;
+	u32	FastIoCommAreaAddress;
+	u32	AdapterFibsPhysicalAddress;
+	u32	AdapterFibsVirtualAddress;
+	u32	AdapterFibsSize;
+	u32	AdapterFibAlign;
+	u32	printfbuf;
+	u32	printfbufsiz;
+	u32	HostPhysMemPages;		// number of 4k pages of host physical memory
+	u32	HostElapsedSeconds;		// number of seconds since 1970.
+};
+
+enum aac_log_level {
+	LOG_INIT			= 10,
+	LOG_INFORMATIONAL		= 20,
+	LOG_WARNING			= 30,
+	LOG_LOW_ERROR			= 40,
+	LOG_MEDIUM_ERROR		= 50,
+	LOG_HIGH_ERROR			= 60,
+	LOG_PANIC			= 70,
+	LOG_DEBUG			= 80,
+	LOG_WINDBG_PRINT		= 90
+};
+
+#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT	0x030b
+#define FSAFS_NTC_FIB_CONTEXT			0x030c
+
+struct aac_dev;
+
+struct adapter_ops
+{
+	void (*adapter_interrupt)(struct aac_dev *dev);
+	void (*adapter_notify)(struct aac_dev *dev, u32 event);
+	void (*adapter_enable_int)(struct aac_dev *dev, u32 event);
+	void (*adapter_disable_int)(struct aac_dev *dev, u32 event);
+};
+
+/*
+ *	Define which interrupt handler needs to be installed
+ */
+
+struct aac_driver_ident
+{
+	u16	vendor;
+	u16	device;
+	u16	subsystem_vendor;
+	u16	subsystem_device;
+	int 	(*init)(struct aac_dev *dev, unsigned long num);
+	char *	name;
+	char *	vname;
+	char *	model;
+};
+
+/*
+ *	The adapter interface specs all queues to be located in the same
+ *	physically contigous block. The host structure that defines the
+ *	commuication queues will assume they are each a seperate physically
+ *	contigous memory region that will support them all being one big
+ *	contigous block. 
+ *	There is a command and response queue for each level and direction of
+ *	commuication. These regions are accessed by both the host and adapter.
+ */
+ 
+struct aac_queue {
+	u64		 	logical;		/* This is the address we give the adapter */
+	struct aac_entry	*base;		   	/* This is the system virtual address */
+	struct aac_qhdr 	headers;       		/* A pointer to the producer and consumer queue headers for this queue */
+	u32	 		entries;	   	/* Number of queue entries on this queue */
+	wait_queue_head_t	qfull;		      	/* Event to wait on if the queue is full */
+	wait_queue_head_t	cmdready;	  	/* Indicates there is a Command ready from the adapter on this queue. */
+                                        		/* This is only valid for adapter to host command queues. */                      
+	spinlock_t	 	*lock;		     	/* Spinlock for this queue must take this lock before accessing the lock */
+	spinlock_t		lockdata;		/* Actual lock (used only on one side of the lock) */
+	unsigned long		SavedIrql;      	/* Previous IRQL when the spin lock is taken */
+	u32			padding;		/* Padding - FIXME - can remove I believe */
+	struct list_head 	cmdq;		   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+                                		        /* only valid for command queues which receive entries from the adapter. */
+	struct list_head	pendingq;		/* A queue of outstanding fib's to the adapter. */
+	unsigned long		numpending;		/* Number of entries on outstanding queue. */
+	struct aac_dev *	dev;			/* Back pointer to adapter structure */
+};
+
+/*
+ *	Message queues. The order here is important, see also the 
+ *	queue type ordering
+ */
+
+struct aac_queue_block
+{
+	struct aac_queue queue[8];
+};
+
+/*
+ *	SaP1 Message Unit Registers
+ */
+ 
+struct sa_drawbridge_CSR {
+						//	 Offset |	Name
+	u32	reserved[10];			//	00h-27h |   Reserved
+	u8	LUT_Offset;			//		28h	|	Looup Table Offset
+	u8	reserved1[3];			// 	29h-2bh	|	Reserved
+	u32	LUT_Data;			//		2ch	|	Looup Table Data	
+	u32	reserved2[26];			//	30h-97h	|	Reserved
+	u16	PRICLEARIRQ;			//		98h	|	Primary Clear Irq
+	u16	SECCLEARIRQ;			//		9ah	|	Secondary Clear Irq
+	u16	PRISETIRQ;			//		9ch	|	Primary Set Irq
+	u16	SECSETIRQ;			//		9eh	|	Secondary Set Irq
+	u16	PRICLEARIRQMASK;		//		a0h	|	Primary Clear Irq Mask
+	u16	SECCLEARIRQMASK;		//		a2h	|	Secondary Clear Irq Mask
+	u16	PRISETIRQMASK;			//		a4h	|	Primary Set Irq Mask
+	u16	SECSETIRQMASK;			//		a6h	|	Secondary Set Irq Mask
+	u32	MAILBOX0;			//		a8h	|	Scratchpad 0
+	u32	MAILBOX1;			//		ach	|	Scratchpad 1
+	u32	MAILBOX2;			//		b0h	|	Scratchpad 2
+	u32	MAILBOX3;			//		b4h	|	Scratchpad 3
+	u32	MAILBOX4;			//		b8h	|	Scratchpad 4
+	u32	MAILBOX5;			//		bch	|	Scratchpad 5
+	u32	MAILBOX6;			//		c0h	|	Scratchpad 6
+	u32	MAILBOX7;			//		c4h	|	Scratchpad 7
+
+	u32	ROM_Setup_Data;			//		c8h | 	Rom Setup and Data
+	u32	ROM_Control_Addr;		//		cch | 	Rom Control and Address
+
+	u32	reserved3[12];			//	d0h-ffh	| 	reserved
+	u32	LUT[64];			// 100h-1ffh|	Lookup Table Entries
+
+	//
+	//  TO DO
+	//	need to add DMA, I2O, UART, etc registers form 80h to 364h
+	//
+
+};
+
+#define Mailbox0	SaDbCSR.MAILBOX0
+#define Mailbox1	SaDbCSR.MAILBOX1
+#define Mailbox2	SaDbCSR.MAILBOX2
+#define Mailbox3	SaDbCSR.MAILBOX3
+#define Mailbox4	SaDbCSR.MAILBOX4
+#define Mailbox5	SaDbCSR.MAILBOX5
+#define Mailbox7	SaDbCSR.MAILBOX7
+	
+#define DoorbellReg_p SaDbCSR.PRISETIRQ
+#define DoorbellReg_s SaDbCSR.SECSETIRQ
+#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
+
+
+#define	DOORBELL_0	cpu_to_le16(0x0001)
+#define DOORBELL_1	cpu_to_le16(0x0002)
+#define DOORBELL_2	cpu_to_le16(0x0004)
+#define DOORBELL_3	cpu_to_le16(0x0008)
+#define DOORBELL_4	cpu_to_le16(0x0010)
+#define DOORBELL_5	cpu_to_le16(0x0020)
+#define DOORBELL_6	cpu_to_le16(0x0040)
+
+	
+#define PrintfReady	DOORBELL_5
+#define PrintfDone	DOORBELL_5
+	
+struct sa_registers {
+	struct sa_drawbridge_CSR	SaDbCSR;			/* 98h - c4h */
+};
+	
+
+#define Sa_MINIPORT_REVISION			1
+
+#define sa_readw(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
+#define sa_readl(AEP,  CSR)		readl(&((AEP)->regs.sa->CSR))
+#define sa_writew(AEP, CSR, value)	writew(value, &((AEP)->regs.sa->CSR))
+#define sa_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.sa->CSR))
+
+/*
+ *	Rx Message Unit Registers
+ */
+
+struct rx_mu_registers {
+						//	 Local	|   PCI*	|	Name
+						//			|		|
+	u32	ARSR;				//	1300h	|	00h	|	APIC Register Select Register
+	u32	reserved0;			//	1304h	|	04h	|	Reserved
+	u32	AWR;				//	1308h	|	08h	|	APIC Window Register
+	u32	reserved1;			//	130Ch	|	0Ch	|	Reserved
+	u32	IMRx[2];			//	1310h	|	10h	|	Inbound Message Registers
+	u32	OMRx[2];			//	1318h	|	18h	|	Outbound Message Registers
+	u32	IDR;				//	1320h	|	20h	|	Inbound Doorbell Register
+	u32	IISR;				//	1324h	|	24h	|	Inbound Interrupt Status Register
+	u32	IIMR;				//	1328h	|	28h	|	Inbound Interrupt Mask Register
+	u32	ODR;				//	132Ch	|	2Ch	|	Outbound Doorbell Register
+	u32	OISR;				//	1330h	|	30h	|	Outbound Interrupt Status Register
+	u32	OIMR;				//	1334h	|	34h	|	Outbound Interrupt Mask Register
+						// * Must access through ATU Inbound Translation Window
+};
+
+struct rx_inbound {
+	u32	Mailbox[8];
+};
+
+#define	InboundMailbox0		IndexRegs.Mailbox[0]
+#define	InboundMailbox1		IndexRegs.Mailbox[1]
+#define	InboundMailbox2		IndexRegs.Mailbox[2]
+#define	InboundMailbox3		IndexRegs.Mailbox[3]
+#define	InboundMailbox4		IndexRegs.Mailbox[4]
+
+#define	INBOUNDDOORBELL_0	cpu_to_le32(0x00000001)
+#define INBOUNDDOORBELL_1	cpu_to_le32(0x00000002)
+#define INBOUNDDOORBELL_2	cpu_to_le32(0x00000004)
+#define INBOUNDDOORBELL_3	cpu_to_le32(0x00000008)
+#define INBOUNDDOORBELL_4	cpu_to_le32(0x00000010)
+#define INBOUNDDOORBELL_5	cpu_to_le32(0x00000020)
+#define INBOUNDDOORBELL_6	cpu_to_le32(0x00000040)
+
+#define	OUTBOUNDDOORBELL_0	cpu_to_le32(0x00000001)
+#define OUTBOUNDDOORBELL_1	cpu_to_le32(0x00000002)
+#define OUTBOUNDDOORBELL_2	cpu_to_le32(0x00000004)
+#define OUTBOUNDDOORBELL_3	cpu_to_le32(0x00000008)
+#define OUTBOUNDDOORBELL_4	cpu_to_le32(0x00000010)
+
+#define InboundDoorbellReg	MUnit.IDR
+#define OutboundDoorbellReg	MUnit.ODR
+
+struct rx_registers {
+	struct rx_mu_registers		MUnit;		// 1300h - 1334h
+	u32				reserved1[6];	// 1338h - 134ch
+	struct rx_inbound		IndexRegs;
+};
+
+#define rx_readb(AEP, CSR)		readb(&((AEP)->regs.rx->CSR))
+#define rx_readl(AEP, CSR)		readl(&((AEP)->regs.rx->CSR))
+#define rx_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rx->CSR))
+#define rx_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rx->CSR))
+
+struct fib;
+
+typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
+
+struct aac_fib_context {
+	s16	 		type;		// used for verification of structure	
+	s16	 		size;
+	u32			jiffies;	// used for cleanup
+	struct list_head	next;		// used to link context's into a linked list
+	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
+	int			wait;		// Set to true when thread is in WaitForSingleObject
+	unsigned long		count;		// total number of FIBs on FibList
+	struct list_head	fibs;
+};
+
+#define MAXIMUM_NUM_CONTAINERS	64		// 4 Luns * 16 Targets
+#define MAXIMUM_NUM_ADAPTERS	8
+
+struct fsa_scsi_hba {
+	unsigned long		size[MAXIMUM_NUM_CONTAINERS];
+	unsigned long		type[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		valid[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		ro[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		locked[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		deleted[MAXIMUM_NUM_CONTAINERS];
+	long			devno[MAXIMUM_NUM_CONTAINERS];
+};
+
+struct fib {
+	void			*next;	/* this is used by the allocator */
+	s16			type;
+	s16			size;
+	/*
+	 *	The Adapter that this I/O is destined for.
+	 */
+	struct aac_dev 		*dev;
+	u64			logicaladdr;	/* 64 bit */
+	/*
+	 *	This is the event the sendfib routine will wait on if the
+	 *	caller did not pass one and this is synch io.
+	 */
+	struct semaphore 	event_wait;
+	spinlock_t		event_lock;
+
+	unsigned long		done;	/* gets set to 1 when fib is complete */
+	fib_callback 		callback;
+	void 			*callback_data;
+	unsigned long		flags;
+	/*
+	 *	The following is used to put this fib context onto the 
+	 *	Outstanding I/O queue.
+	 */
+	struct list_head	queue;
+
+	void 			*data;
+	struct hw_fib		*fib;		/* Actual shared object */
+};
+
+struct aac_dev
+{
+	struct aac_dev		*next;
+	const char		*name;
+	int			id;
+
+	u16			irq_mask;
+	/*
+	 *	Map for 128 fib objects (64k)
+	 */	
+	dma_addr_t		hw_fib_pa;
+	struct hw_fib		*hw_fib_va;
+	/*
+	 *	Fib Headers
+	 */
+	struct fib		fibs[AAC_NUM_FIB];
+	struct fib		*free_fib;
+	struct fib		*timeout_fib;
+	spinlock_t		fib_lock;
+	
+	struct aac_queue_block *queues;
+	/*
+	 *	The user API will use an IOCTL to register itself to receive
+	 *	FIBs from the adapter.  The following list is used to keep
+	 *	track of all the threads that have requested these FIBs.  The
+	 *	mutex is used to synchronize access to all data associated 
+	 *	with the adapter fibs.
+	 */
+	struct list_head	fib_list;
+
+	struct adapter_ops	a_ops;
+	unsigned long		fsrev;		/* Main driver's revision number */
+	
+	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
+	void *			init_pa; 	/* Holds physical address of the init struct */
+	
+	struct pci_dev		*pdev;		/* Our PCI interface */
+	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
+	void *			comm_addr;	/* Base address of Comm area */
+	dma_addr_t		comm_phys;	/* Physical Address of Comm area */
+	size_t			comm_size;
+
+	struct Scsi_Host	*scsi_host_ptr;
+	struct fsa_scsi_hba	fsa_dev;
+	int			thread_pid;
+	int			cardtype;
+	
+	/*
+	 *	The following is the device specific extension.
+	 */
+	union
+	{
+		struct sa_registers *sa;
+		struct rx_registers *rx;
+	} regs;
+	/*
+	 *	The following is the number of the individual adapter
+	 */
+	long			devnum;
+	int			aif_thread;
+	struct completion	aif_completion;
+};
+
+#define AllocateAndMapFibSpace(dev, MapFibContext) \
+	dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext)
+
+#define UnmapAndFreeFibSpace(dev, MapFibContext) \
+	dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext)
+
+#define aac_adapter_interrupt(dev) \
+	dev->a_ops.adapter_interrupt(dev)
+
+#define aac_adapter_notify(dev, event) \
+	dev->a_ops.adapter_notify(dev, event)
+
+#define aac_adapter_enable_int(dev, event) \
+	dev->a_ops.adapter_enable_int(dev, event)
+
+#define aac_adapter_disable_int(dev, event) \
+	dev->a_ops.adapter_disable_int(dev, event)
+
+
+
+#define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
+
+/*
+ *	Define the command values
+ */
+ 
+#define		Null			0
+#define 	GetAttributes		1
+#define 	SetAttributes		2
+#define 	Lookup			3
+#define 	ReadLink		4
+#define 	Read			5
+#define 	Write			6
+#define		Create			7
+#define		MakeDirectory		8
+#define		SymbolicLink		9
+#define		MakeNode		10
+#define		Removex			11
+#define		RemoveDirectoryx	12
+#define		Rename			13
+#define		Link			14
+#define		ReadDirectory		15
+#define		ReadDirectoryPlus	16
+#define		FileSystemStatus	17
+#define		FileSystemInfo		18
+#define		PathConfigure		19
+#define		Commit			20
+#define		Mount			21
+#define		UnMount			22
+#define		Newfs			23
+#define		FsCheck			24
+#define		FsSync			25
+#define		SimReadWrite		26
+#define		SetFileSystemStatus	27
+#define		BlockRead		28
+#define		BlockWrite		29
+#define		NvramIoctl		30
+#define		FsSyncWait		31
+#define		ClearArchiveBit		32
+#define		SetAcl			33
+#define		GetAcl			34
+#define		AssignAcl		35
+#define		FaultInsertion		36	/* Fault Insertion Command */
+#define		CrazyCache		37	/* Crazycache */
+
+#define		MAX_FSACOMMAND_NUM	38
+
+
+/*
+ *	Define the status returns. These are very unixlike although
+ *	most are not in fact used
+ */
+
+#define		ST_OK		0
+#define		ST_PERM		1
+#define		ST_NOENT	2
+#define		ST_IO		5
+#define		ST_NXIO		6
+#define		ST_E2BIG	7
+#define		ST_ACCES	13
+#define		ST_EXIST	17
+#define		ST_XDEV		18
+#define		ST_NODEV	19
+#define		ST_NOTDIR	20
+#define		ST_ISDIR	21
+#define		ST_INVAL	22
+#define		ST_FBIG		27
+#define		ST_NOSPC	28
+#define		ST_ROFS		30
+#define		ST_MLINK	31
+#define		ST_WOULDBLOCK	35
+#define		ST_NAMETOOLONG	63
+#define		ST_NOTEMPTY	66
+#define		ST_DQUOT	69
+#define		ST_STALE	70
+#define		ST_REMOTE	71
+#define		ST_BADHANDLE	10001
+#define		ST_NOT_SYNC	10002
+#define		ST_BAD_COOKIE	10003
+#define		ST_NOTSUPP	10004
+#define		ST_TOOSMALL	10005
+#define		ST_SERVERFAULT	10006
+#define		ST_BADTYPE	10007
+#define		ST_JUKEBOX	10008
+#define		ST_NOTMOUNTED	10009
+#define		ST_MAINTMODE	10010
+#define		ST_STALEACL	10011
+
+/*
+ *	On writes how does the client want the data written.
+ */
+
+#define	CACHE_CSTABLE		1
+#define CACHE_UNSTABLE		2
+
+/*
+ *	Lets the client know at which level the data was commited on
+ *	a write request
+ */
+
+#define	CMFILE_SYNCH_NVRAM	1
+#define	CMDATA_SYNCH_NVRAM	2
+#define	CMFILE_SYNCH		3
+#define CMDATA_SYNCH		4
+#define CMUNSTABLE		5
+
+struct aac_read
+{
+	u32	 	command;
+	u32 		cid;
+	u32 		block;
+	u32 		count;
+	struct sgmap	sg;	// Must be last in struct because it is variable
+};
+
+struct aac_read_reply
+{
+	u32	 	status;
+	u32 		count;
+};
+
+struct aac_write
+{
+	u32		command;
+	u32 		cid;
+	u32 		block;
+	u32 		count;
+	u32	 	stable;
+	struct sgmap	sg;	// Must be last in struct because it is variable
+};
+
+struct aac_write_reply
+{
+	u32		status;
+	u32 		count;
+	u32		committed;
+};
+
+
+/*
+ * Object-Server / Volume-Manager Dispatch Classes
+ */
+
+#define		VM_Null			0
+#define		VM_NameServe		1
+#define		VM_ContainerConfig	2
+#define		VM_Ioctl		3
+#define		VM_FilesystemIoctl	4
+#define		VM_CloseAll		5
+#define		VM_CtBlockRead		6
+#define		VM_CtBlockWrite		7
+#define		VM_SliceBlockRead	8	/* raw access to configured "storage objects" */
+#define		VM_SliceBlockWrite	9
+#define		VM_DriveBlockRead	10	/* raw access to physical devices */
+#define		VM_DriveBlockWrite	11
+#define		VM_EnclosureMgt		12	/* enclosure management */
+#define		VM_Unused		13	/* used to be diskset management */
+#define		VM_CtBlockVerify	14
+#define		VM_CtPerf		15	/* performance test */
+#define		VM_CtBlockRead64	16
+#define		VM_CtBlockWrite64	17
+#define		VM_CtBlockVerify64	18
+
+#define		MAX_VMCOMMAND_NUM	19	/* used for sizing stats array - leave last */
+
+/*
+ *	Descriptive information (eg, vital stats)
+ *	that a content manager might report.  The
+ *	FileArray filesystem component is one example
+ *	of a content manager.  Raw mode might be
+ *	another.
+ */
+
+struct aac_fsinfo {
+	u32  fsTotalSize;	/* Consumed by fs, incl. metadata */
+	u32  fsBlockSize;
+	u32  fsFragSize;
+	u32  fsMaxExtendSize;
+	u32  fsSpaceUnits;
+	u32  fsMaxNumFiles;
+	u32  fsNumFreeFiles;
+	u32  fsInodeDensity;
+};	/* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */
+
+union aac_contentinfo {
+	struct aac_fsinfo filesys;	/* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */
+};
+
+/*
+ *	Query for "mountable" objects, ie, objects that are typically
+ *	associated with a drive letter on the client (host) side.
+ */
+
+struct aac_mntent {
+	u32    			oid;
+	char			name[16];	// if applicable
+	struct creation_info	create_info;	// if applicable
+	u32			capacity;
+	u32			vol;    	// substrate structure
+	u32			obj;	        // FT_FILESYS, FT_DATABASE, etc.
+	u32			state;		// unready for mounting, readonly, etc.
+	union aac_contentinfo	fileinfo;	// Info specific to content manager (eg, filesystem)
+	u32			altoid;		// != oid <==> snapshot or broken mirror exists
+};
+
+#define FSCS_READONLY	0x0002	/*	possible result of broken mirror */
+
+struct aac_query_mount {
+	u32		command;
+	u32		type;
+	u32		count;
+};
+
+struct aac_mount {
+	u32		status;
+	u32	   	type;           /* should be same as that requested */
+	u32		count;
+	struct aac_mntent mnt[1];
+};
+
+/*
+ * The following command is sent to shut down each container.
+ */
+
+struct aac_close {
+	u32	command;
+	u32	cid;
+};
+
+struct aac_query_disk
+{
+	s32	cnum;
+	s32	bus;
+	s32	target;
+	s32	lun;
+	u32	valid;
+	u32	locked;
+	u32	deleted;
+	s32	instance;
+	s8	name[10];
+	u32	unmapped;
+};
+
+struct aac_delete_disk {
+	u32	disknum;
+	u32	cnum;
+};
+
+struct fib_ioctl
+{
+	char	*fibctx;
+	int	wait;
+	char	*fib;
+};
+
+struct revision
+{
+	int compat;
+	unsigned long version;
+	unsigned long build;
+};
+	
+/*
+ * 	Ugly - non Linux like ioctl coding for back compat.
+ */
+
+#define CTL_CODE(function, method) (                 \
+    (4<< 16) | ((function) << 2) | (method) \
+)
+
+/*
+ *	Define the method codes for how buffers are passed for I/O and FS 
+ *	controls
+ */
+
+#define METHOD_BUFFERED                 0
+#define METHOD_NEITHER                  3
+
+/*
+ *	Filesystem ioctls
+ */
+
+#define FSACTL_SENDFIB                  	CTL_CODE(2050, METHOD_BUFFERED)
+#define FSACTL_DELETE_DISK			0x163
+#define FSACTL_QUERY_DISK			0x173
+#define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(2100, METHOD_BUFFERED)
+#define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(2101, METHOD_BUFFERED)
+#define FSACTL_CLOSE_GET_ADAPTER_FIB		CTL_CODE(2102, METHOD_BUFFERED)
+#define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
+#define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
+
+struct aac_common
+{
+	/*
+	 *	If this value is set to 1 then interrupt moderation will occur 
+	 *	in the base commuication support.
+	 */
+	unsigned long irq_mod;
+	int peak_fibs;
+	int zero_fibs;
+	unsigned long fib_timeouts;
+	/*
+	 *	Statistical counters in debug mode
+	 */
+#ifdef DBG
+	unsigned long FibsSent;
+	unsigned long FibRecved;
+	unsigned long NoResponseSent;
+	unsigned long NoResponseRecved;
+	unsigned long AsyncSent;
+	unsigned long AsyncRecved;
+	unsigned long NormalSent;
+	unsigned long NormalRecved;
+#endif
+};
+
+extern struct aac_common aac_config;
+
+
+/*
+ *	The following macro is used when sending and receiving FIBs. It is
+ *	only used for debugging.
+ */
+ 
+#if DBG
+#define	FIB_COUNTER_INCREMENT(counter)		(counter)++
+#else
+#define	FIB_COUNTER_INCREMENT(counter)		
+#endif
+
+/*
+ *	Adapter direct commands
+ */
+
+#define	BREAKPOINT_REQUEST		0x00000004
+#define	INIT_STRUCT_BASE_ADDRESS	0x00000005
+#define	SEND_SYNCHRONOUS_FIB		0x0000000c
+
+/*
+ *	Adapter Status Register
+ *
+ *  Phase Staus mailbox is 32bits:
+ *	<31:16> = Phase Status
+ *	<15:0>  = Phase
+ *
+ *	The adapter reports is present state through the phase.  Only
+ *	a single phase should be ever be set.  Each phase can have multiple
+ *	phase status bits to provide more detailed information about the 
+ *	state of the board.  Care should be taken to ensure that any phase 
+ *	status bits that are set when changing the phase are also valid
+ *	for the new phase or be cleared out.  Adapter software (monitor,
+ *	iflash, kernel) is responsible for properly maintining the phase 
+ *	status mailbox when it is running.
+ *											
+ *	MONKER_API Phases							
+ *
+ *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
+ */					
+
+#define	SELF_TEST_FAILED		cpu_to_le32(0x00000004)
+#define	KERNEL_UP_AND_RUNNING		cpu_to_le32(0x00000080)
+#define	KERNEL_PANIC			cpu_to_le32(0x00000100)
+
+/*
+ *	Doorbell bit defines
+ */
+
+#define DoorBellPrintfDone		cpu_to_le32(1<<5)	// Host -> Adapter
+#define DoorBellAdapterNormCmdReady	cpu_to_le32(1<<1)	// Adapter -> Host
+#define DoorBellAdapterNormRespReady	cpu_to_le32(1<<2)	// Adapter -> Host
+#define DoorBellAdapterNormCmdNotFull	cpu_to_le32(1<<3)	// Adapter -> Host
+#define DoorBellAdapterNormRespNotFull	cpu_to_le32(1<<4)	// Adapter -> Host
+#define DoorBellPrintfReady		cpu_to_le32(1<<5)	// Adapter -> Host
+
+/*
+ *	For FIB communication, we need all of the following things
+ *	to send back to the user.
+ */
+ 
+#define 	AifCmdEventNotify	1	/* Notify of event */
+#define		AifCmdJobProgress	2	/* Progress report */
+#define		AifCmdAPIReport		3	/* Report from other user of API */
+#define		AifCmdDriverNotify	4	/* Notify host driver of event */
+#define		AifReqJobList		100	/* Gets back complete job list */
+#define		AifReqJobsForCtr	101	/* Gets back jobs for specific container */
+#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */ 
+#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */ 
+#define		AifReqTerminateJob	104	/* Terminates job */
+#define		AifReqSuspendJob	105	/* Suspends a job */
+#define		AifReqResumeJob		106	/* Resumes a job */ 
+#define		AifReqSendAPIReport	107	/* API generic report requests */
+#define		AifReqAPIJobStart	108	/* Start a job from the API */
+#define		AifReqAPIJobUpdate	109	/* Update a job report from the API */
+#define		AifReqAPIJobFinish	110	/* Finish a job from the API */
+
+/*
+ *	Adapter Initiated FIB command structures. Start with the adapter
+ *	initiated FIBs that really come from the adapter, and get responded
+ *	to by the host.
+ */
+
+struct aac_aifcmd {
+	u32 command;		/* Tell host what type of notify this is */
+	u32 seqnum;		/* To allow ordering of reports (if necessary) */
+	u8 data[1];		/* Undefined length (from kernel viewpoint) */
+};
+
+/*
+ *	Adapter Information Block
+ *
+ *	This is returned by the RequestAdapterInfo block
+ */
+ 
+struct aac_adapter_info
+{
+	u32	platform;
+	u32	cpu;
+	u32	subcpu;
+	u32	clock;
+	u32	execmem;
+	u32	buffermem;
+	u32	totalmem;
+	u32	kernelrev;
+	u32	kernelbuild;
+	u32	monitorrev;
+	u32	monitorbuild;
+	u32	hwrev;
+	u32	hwbuild;
+	u32	biosrev;
+	u32	biosbuild;
+	u32	clustering;
+	u32	clustermask;
+	u64	serial;
+	u32	battery;
+	u32	options;
+	u32	OEM;
+};
+	
+const char *aac_driverinfo(struct Scsi_Host *);
+struct fib *fib_alloc(struct aac_dev *dev);
+int fib_setup(struct aac_dev *dev);
+void fib_map_free(struct aac_dev *dev);
+void fib_free(struct fib * context);
+void fib_init(struct fib * context);
+void fib_dealloc(struct fib * context);
+void aac_printf(struct aac_dev *dev, u32 val);
+int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
+int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
+int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q);
+void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
+int fib_complete(struct fib * context);
+#define fib_data(fibctx) ((void *)(fibctx)->fib->data)
+int aac_detach(struct aac_dev *dev);
+struct aac_dev *aac_init_adapter(struct aac_dev *dev);
+int aac_get_containers(struct aac_dev *dev);
+int aac_scsi_cmd(Scsi_Cmnd *scsi_cmnd_ptr);
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg);
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg);
+int aac_rx_init(struct aac_dev *dev, unsigned long devNumber);
+int aac_sa_init(struct aac_dev *dev, unsigned long devNumber);
+unsigned int aac_response_normal(struct aac_queue * q);
+unsigned int aac_command_normal(struct aac_queue * q);
+int aac_command_thread(struct aac_dev * dev);
+int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
+int fib_adapter_complete(struct fib * fibptr, unsigned short size);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/commctrl.c linux/drivers/scsi/aacraid/commctrl.c
--- linux-2.4.16/drivers/scsi/aacraid/commctrl.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/commctrl.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,410 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  commctrl.c
+ *
+ * Abstract: Contains all routines for control of the AFA comm layer
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/blk.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+/**
+ *	ioctl_send_fib	-	send a FIB from userspace
+ *	@dev:	adapter is being processed
+ *	@arg:	arguments to the ioctl call
+ *	
+ *	This routine sends a fib to the adapter on behalf of a user level
+ *	program.
+ */
+ 
+static int ioctl_send_fib(struct aac_dev * dev, void *arg)
+{
+	struct hw_fib * kfib;
+	struct fib *fibptr;
+
+	fibptr = fib_alloc(dev);
+	if(fibptr == NULL)
+		return -ENOMEM;
+		
+	kfib = fibptr->fib;
+	/*
+	 *	First copy in the header so that we can check the size field.
+	 */
+	if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
+		fib_free(fibptr);
+		return -EFAULT;
+	}
+	/*
+	 *	Since we copy based on the fib header size, make sure that we
+	 *	will not overrun the buffer when we copy the memory. Return
+	 *	an error if we would.
+	 */
+	if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
+		fib_free(fibptr);
+		return -EINVAL;
+	}
+
+	if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) {
+		fib_free(fibptr);
+		return -EFAULT;
+	}
+
+	if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) {
+		aac_adapter_interrupt(dev);
+		/*
+		 * Since we didn't really send a fib, zero out the state to allow 
+		 * cleanup code not to assert.
+		 */
+		kfib->header.XferState = 0;
+	} else {
+		if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal,
+			1, 1, NULL, NULL) != 0) 
+		{
+			fib_free(fibptr);
+			return -EINVAL;
+		}
+		if (fib_complete(fibptr) != 0) {
+			fib_free(fibptr);
+			return -EINVAL;
+		}
+	}
+	/*
+	 *	Make sure that the size returned by the adapter (which includes
+	 *	the header) is less than or equal to the size of a fib, so we
+	 *	don't corrupt application data. Then copy that size to the user
+	 *	buffer. (Don't try to add the header information again, since it
+	 *	was already included by the adapter.)
+	 */
+
+	if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) {
+		fib_free(fibptr);
+		return -EFAULT;
+	}
+	fib_free(fibptr);
+	return 0;
+}
+
+/**
+ *	open_getadapter_fib	-	Get the next fib
+ *
+ *	This routine will get the next Fib, if available, from the AdapterFibContext
+ *	passed in from the user.
+ */
+
+static int open_getadapter_fib(struct aac_dev * dev, void *arg)
+{
+	struct aac_fib_context * fibctx;
+	int status;
+	unsigned long flags;
+
+	fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
+	if (fibctx == NULL) {
+		status = -ENOMEM;
+	} else {
+		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
+		fibctx->size = sizeof(struct aac_fib_context);
+		/*
+		 *	Initialize the mutex used to wait for the next AIF.
+		 */
+		init_MUTEX_LOCKED(&fibctx->wait_sem);
+		fibctx->wait = 0;
+		/*
+		 *	Initialize the fibs and set the count of fibs on
+		 *	the list to 0.
+		 */
+		fibctx->count = 0;
+		INIT_LIST_HEAD(&fibctx->fibs);
+		fibctx->jiffies = jiffies/HZ;
+		/*
+		 *	Now add this context onto the adapter's 
+		 *	AdapterFibContext list.
+		 */
+		spin_lock_irqsave(&dev->fib_lock, flags);
+		list_add_tail(&fibctx->next, &dev->fib_list);
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		if (copy_to_user(arg,  &fibctx, sizeof(struct aac_fib_context *))) {
+			status = -EFAULT;
+		} else {
+			status = 0;
+		}	
+	}
+	return status;
+}
+
+/**
+ *	next_getadapter_fib	-	get the next fib
+ *	@dev: adapter to use
+ *	@arg: ioctl argument
+ *	
+ * 	This routine will get the next Fib, if available, from the AdapterFibContext
+ *	passed in from the user.
+ */
+
+static int next_getadapter_fib(struct aac_dev * dev, void *arg)
+{
+	struct fib_ioctl f;
+	struct aac_fib_context *fibctx, *aifcp;
+	struct hw_fib * fib;
+	int status;
+	struct list_head * entry;
+	int found;
+	unsigned long flags;
+	
+	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
+		return -EFAULT;
+	/*
+	 *	Extract the AdapterFibContext from the Input parameters.
+	 */
+	fibctx = (struct aac_fib_context *) f.fibctx;
+
+	/*
+	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
+	 *
+	 *	Search the list of AdapterFibContext addresses on the adapter
+	 *	to be sure this is a valid address
+	 */
+	found = 0;
+	entry = dev->fib_list.next;
+
+	while(entry != &dev->fib_list) {
+		aifcp = list_entry(entry, struct aac_fib_context, next);
+		if(fibctx == aifcp) {   /* We found a winner */
+			found = 1;
+			break;
+		}
+		entry = entry->next;
+	}
+	if (found == 0)
+		return -EINVAL;
+
+	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+		 (fibctx->size != sizeof(struct aac_fib_context)))
+		return -EINVAL;
+	status = 0;
+	spin_lock_irqsave(&dev->fib_lock, flags);
+	/*
+	 *	If there are no fibs to send back, then either wait or return
+	 *	-EAGAIN
+	 */
+return_fib:
+	if (!list_empty(&fibctx->fibs)) {
+		struct list_head * entry;
+		/*
+		 *	Pull the next fib from the fibs
+		 */
+		entry = fibctx->fibs.next;
+		list_del(entry);
+		
+		fib = list_entry(entry, struct hw_fib, header.FibLinks);
+		fibctx->count--;
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		if (copy_to_user(f.fib, fib, sizeof(struct hw_fib))) {
+			kfree(fib);
+			return -EFAULT;
+		}	
+		/*
+		 *	Free the space occupied by this copy of the fib.
+		 */
+		kfree(fib);
+		status = 0;
+		fibctx->jiffies = jiffies/HZ;
+	} else {
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		if (f.wait) {
+			if(down_interruptible(&fibctx->wait_sem) < 0) {
+				status = -EINTR;
+			} else {
+				/* Lock again and retry */
+				spin_lock_irqsave(&dev->fib_lock, flags);
+				goto return_fib;
+			}
+		} else {
+			status = -EAGAIN;
+		}	
+	}
+	return status;
+}
+
+int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
+{
+	struct hw_fib *fib;
+
+	/*
+	 *	First free any FIBs that have not been consumed.
+	 */
+	while (!list_empty(&fibctx->fibs)) {
+		struct list_head * entry;
+		/*
+		 *	Pull the next fib from the fibs
+		 */
+		entry = fibctx->fibs.next;
+		list_del(entry);
+		fib = list_entry(entry, struct hw_fib, header.FibLinks);
+		fibctx->count--;
+		/*
+		 *	Free the space occupied by this copy of the fib.
+		 */
+		kfree(fib);
+	}
+	/*
+	 *	Remove the Context from the AdapterFibContext List
+	 */
+	list_del(&fibctx->next);
+	/*
+	 *	Invalidate context
+	 */
+	fibctx->type = 0;
+	/*
+	 *	Free the space occupied by the Context
+	 */
+	kfree(fibctx);
+	return 0;
+}
+
+/**
+ *	close_getadapter_fib	-	close down user fib context
+ *	@dev: adapter
+ *	@arg: ioctl arguments
+ *
+ *	This routine will close down the fibctx passed in from the user.
+ */
+ 
+static int close_getadapter_fib(struct aac_dev * dev, void *arg)
+{
+	struct aac_fib_context *fibctx, *aifcp;
+	int status;
+	unsigned long flags;
+	struct list_head * entry;
+	int found;
+
+	/*
+	 *	Extract the fibctx from the input parameters
+	 */
+	fibctx = arg;
+
+	/*
+	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
+	 *
+	 *	Search the list of AdapterFibContext addresses on the adapter
+	 *	to be sure this is a valid address
+	 */
+
+	found = 0;
+	entry = dev->fib_list.next;
+
+	while(entry != &dev->fib_list) {
+		aifcp = list_entry(entry, struct aac_fib_context, next);
+		if(fibctx == aifcp) {   /* We found a winner */
+			found = 1;
+			break;
+		}
+		entry = entry->next;
+	}
+
+	if(found == 0)
+		return 0; /* Already gone */
+
+	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+		 (fibctx->size != sizeof(struct aac_fib_context)))
+		return -EINVAL;
+	spin_lock_irqsave(&dev->fib_lock, flags);
+	status = aac_close_fib_context(dev, fibctx);
+	spin_unlock_irqrestore(&dev->fib_lock, flags);
+	return status;
+}
+
+/**
+ *	check_revision	-	close down user fib context
+ *	@dev: adapter
+ *	@arg: ioctl arguments
+ *
+ *	This routine returns the firmware version.
+ *      Under Linux, there have been no version incompatibilities, so this is simple!
+ */
+
+static int check_revision(struct aac_dev *dev, void *arg)
+{
+	struct revision response;
+
+	response.compat = 1;
+	response.version = 0x03000400;
+	response.build = 0x5125;
+
+	if (copy_to_user(arg, &response, sizeof(response)))
+		return -EFAULT;
+	return 0;
+}
+
+
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg)
+{
+	int status;
+	
+	/*
+	 *	HBA gets first crack
+	 */
+	 
+	status = aac_dev_ioctl(dev, cmd, arg);
+	if(status != -ENOTTY)
+		return status;
+
+	switch (cmd) {
+	case FSACTL_MINIPORT_REV_CHECK:
+		status = check_revision(dev, arg);
+		break;
+	case FSACTL_SENDFIB:
+		status = ioctl_send_fib(dev, arg);
+		break;
+	case FSACTL_OPEN_GET_ADAPTER_FIB:
+		status = open_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_GET_NEXT_ADAPTER_FIB:
+		status = next_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_CLOSE_GET_ADAPTER_FIB:
+		status = close_getadapter_fib(dev, arg);
+		break;
+	default:
+		status = -ENOTTY;
+	  	break;	
+	}
+	return status;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/comminit.c linux/drivers/scsi/aacraid/comminit.c
--- linux-2.4.16/drivers/scsi/aacraid/comminit.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/comminit.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,332 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  comminit.c
+ *
+ * Abstract: This supports the initialization of the host adapter commuication interface.
+ *    This is a platform dependent module for the pci cyclone board.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blk.h>
+#include <asm/semaphore.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+struct aac_common aac_config;
+
+static struct aac_dev *devices;
+
+static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
+{
+	unsigned char *base;
+	unsigned long size, align;
+	unsigned long fibsize = 4096;
+	unsigned long printfbufsiz = 256;
+	struct aac_init *init;
+	dma_addr_t phys;
+
+	size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
+
+	base = pci_alloc_consistent(dev->pdev, size, &phys);
+	if(base == NULL)
+	{
+		printk(KERN_ERR "aacraid: unable to create mapping.\n");
+		return 0;
+	}
+	dev->comm_addr  = (void *)base;
+	dev->comm_phys = phys;
+	dev->comm_size     = size;
+
+	dev->init = (struct aac_init *)(base + fibsize);
+	dev->init_pa = (struct aac_init *)(phys + fibsize);
+
+	init = dev->init;
+
+	init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
+	init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION);
+	init->fsrev = cpu_to_le32(dev->fsrev);
+
+	/*
+	 *	Adapter Fibs are the first thing allocated so that they
+	 *	start page aligned
+	 */
+	init->AdapterFibsVirtualAddress = cpu_to_le32(base);
+	init->AdapterFibsPhysicalAddress = cpu_to_le32(phys);
+	init->AdapterFibsSize = cpu_to_le32(fibsize);
+	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
+
+	/*
+	 * Increment the base address by the amount already used
+	 */
+	base = base + fibsize + sizeof(struct aac_init);
+	phys = phys + fibsize + sizeof(struct aac_init);
+	/*
+	 *	Align the beginning of Headers to commalign
+	 */
+	align = (commalign - ((unsigned long)(base) & (commalign - 1)));
+	base = base + align;
+	phys = phys + align;
+	/*
+	 *	Fill in addresses of the Comm Area Headers and Queues
+	 */
+	*commaddr = (unsigned long *)base;
+	init->CommHeaderAddress = cpu_to_le32(phys);
+	/*
+	 *	Increment the base address by the size of the CommArea
+	 */
+	base = base + commsize;
+	phys = phys + commsize;
+	/*
+	 *	 Place the Printf buffer area after the Fast I/O comm area.
+	 */
+	dev->printfbuf = (void *)base;
+	init->printfbuf = cpu_to_le32(phys);
+	init->printfbufsiz = cpu_to_le32(printfbufsiz);
+	memset(base, 0, printfbufsiz);
+	return 1;
+}
+    
+static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize)
+{
+	q->numpending = 0;
+	q->dev = dev;
+	INIT_LIST_HEAD(&q->pendingq);
+	init_waitqueue_head(&q->cmdready);
+	INIT_LIST_HEAD(&q->cmdq);
+	init_waitqueue_head(&q->qfull);
+	spin_lock_init(&q->lockdata);
+	q->lock = &q->lockdata;
+	q->headers.producer = mem;
+	q->headers.consumer = mem+1;
+	*q->headers.producer = cpu_to_le32(qsize);
+	*q->headers.consumer = cpu_to_le32(qsize);
+	q->entries = qsize;
+}
+
+/**
+ *	aac_send_shutdown		-	shutdown an adapter
+ *	@dev: Adapter to shutdown
+ *
+ *	This routine will send a VM_CloseAll (shutdown) request to the adapter.
+ */
+
+static int aac_send_shutdown(struct aac_dev * dev)
+{
+	struct fib * fibctx;
+	struct aac_close *cmd;
+	int status;
+
+	fibctx = fib_alloc(dev);
+	fib_init(fibctx);
+
+	cmd = (struct aac_close *) fib_data(fibctx);
+
+	cmd->command = cpu_to_le32(VM_CloseAll);
+	cmd->cid = cpu_to_le32(0xffffffff);
+
+	status = fib_send(ContainerCommand,
+			  fibctx,
+			  sizeof(struct aac_close),
+			  FsaNormal,
+			  1, 1,
+			  NULL, NULL);
+
+	if (status == 0)
+		fib_complete(fibctx);
+	fib_free(fibctx);
+	return status;
+}
+
+/**
+ *	aac_detach	-	detach adapter
+ *	@detach: adapter to disconnect
+ *
+ *	Disconnect and shutdown an AAC based adapter, freeing resources
+ *	as we go.
+ */
+
+int aac_detach(struct aac_dev *detach)
+{
+	struct aac_dev **dev = &devices;
+	
+	while(*dev)
+	{
+		if(*dev == detach)
+		{
+			*dev = detach->next;
+			aac_send_shutdown(detach);
+			fib_map_free(detach);
+			pci_free_consistent(detach->pdev, detach->comm_size, detach->comm_addr, detach->comm_phys);
+			kfree(detach->queues);
+			return 1;
+		}
+		dev=&((*dev)->next);
+	}
+	BUG();
+	return 0;
+}
+
+/**
+ *	aac_comm_init	-	Initialise FSA data structures
+ *	@dev:	Adapter to intialise
+ *
+ *	Initializes the data structures that are required for the FSA commuication
+ *	interface to operate. 
+ *	Returns
+ *		1 - if we were able to init the commuication interface.
+ *		0 - If there were errors initing. This is a fatal error.
+ */
+ 
+int aac_comm_init(struct aac_dev * dev)
+{
+	unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2;
+	unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES;
+	u32 *headers;
+	struct aac_entry * queues;
+	unsigned long size;
+	struct aac_queue_block * comm = dev->queues;
+
+	/*
+	 *	Now allocate and initialize the zone structures used as our 
+	 *	pool of FIB context records.  The size of the zone is based
+	 *	on the system memory size.  We also initialize the mutex used
+	 *	to protect the zone.
+	 */
+	spin_lock_init(&dev->fib_lock);
+
+	/*
+	 *	Allocate the physically contigous space for the commuication
+	 *	queue headers. 
+	 */
+
+	size = hdrsize + queuesize;
+
+	if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT))
+		return -ENOMEM;
+
+	queues = (struct aac_entry *)((unsigned char *)headers + hdrsize);
+
+	/* Adapter to Host normal priority Command queue */ 
+	comm->queue[HostNormCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES);
+	queues += HOST_NORM_CMD_ENTRIES;
+	headers += 2;
+
+	/* Adapter to Host high priority command queue */
+	comm->queue[HostHighCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES);
+    
+	queues += HOST_HIGH_CMD_ENTRIES;
+	headers +=2;
+
+	/* Host to adapter normal priority command queue */
+	comm->queue[AdapNormCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES);
+    
+	queues += ADAP_NORM_CMD_ENTRIES;
+	headers += 2;
+
+	/* host to adapter high priority command queue */
+	comm->queue[AdapHighCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES);
+    
+	queues += ADAP_HIGH_CMD_ENTRIES;
+	headers += 2;
+
+	/* adapter to host normal priority response queue */
+	comm->queue[HostNormRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES);
+    
+	queues += HOST_NORM_RESP_ENTRIES;
+	headers += 2;
+
+	/* adapter to host high priority response queue */
+	comm->queue[HostHighRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES);
+   
+	queues += HOST_HIGH_RESP_ENTRIES;
+	headers += 2;
+
+	/* host to adapter normal priority response queue */
+	comm->queue[AdapNormRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES);
+
+	queues += ADAP_NORM_RESP_ENTRIES;
+	headers += 2;
+	
+	/* host to adapter high priority response queue */ 
+	comm->queue[AdapHighRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES);
+
+	comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock;
+	comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock;
+	comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock;
+	comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock;
+
+	return 0;
+}
+
+struct aac_dev *aac_init_adapter(struct aac_dev *dev)
+{
+	/*
+	 *	Ok now init the communication subsystem
+	 */
+	dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+	if (dev->queues == NULL) {
+		printk(KERN_ERR "Error could not allocate comm region.\n");
+		return NULL;
+	}
+	memset(dev->queues, 0, sizeof(struct aac_queue_block));
+
+	if (aac_comm_init(dev)<0)
+		return NULL;
+	/*
+	 *	Initialize the list of fibs
+	 */
+	if(fib_setup(dev)<0)
+		return NULL;
+		
+	INIT_LIST_HEAD(&dev->fib_list);
+	spin_lock_init(&dev->fib_lock);
+	init_completion(&dev->aif_completion);
+	/*
+	 *	Add this adapter in to our dev List.
+	 */
+	dev->next = devices;
+	devices = dev;
+	return dev;
+}
+
+    
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/commsup.c linux/drivers/scsi/aacraid/commsup.c
--- linux-2.4.16/drivers/scsi/aacraid/commsup.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/commsup.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,944 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  commsup.c
+ *
+ * Abstract: Contain all routines that are required for FSA host/adapter
+ *    commuication.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+/**
+ *	fib_map_alloc		-	allocate the fib objects
+ *	@dev: Adapter to allocate for
+ *
+ *	Allocate and map the shared PCI space for the FIB blocks used to
+ *	talk to the Adaptec firmware.
+ */
+ 
+static int fib_map_alloc(struct aac_dev *dev)
+{
+	if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, &dev->hw_fib_pa))==NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+/**
+ *	fib_map_free		-	free the fib objects
+ *	@dev: Adapter to free
+ *
+ *	Free the PCI mappings and the memory allocated for FIB blocks
+ *	on this adapter.
+ */
+
+void fib_map_free(struct aac_dev *dev)
+{
+	pci_free_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, dev->hw_fib_va, dev->hw_fib_pa);
+}
+
+/**
+ *	fib_setup	-	setup the fibs
+ *	@dev: Adapter to set up
+ *
+ *	Allocate the PCI space for the fibs, map it and then intialise the
+ *	fib area, the unmapped fib data and also the free list
+ */
+
+int fib_setup(struct aac_dev * dev)
+{
+	struct fib *fibptr;
+	struct hw_fib *fib;
+	dma_addr_t fibpa;
+	int i;
+	
+	if(fib_map_alloc(dev)<0)
+		return -ENOMEM;
+		
+	fib = dev->hw_fib_va;
+	fibpa = dev->hw_fib_pa;
+	memset(fib, 0, sizeof(struct hw_fib) * AAC_NUM_FIB);
+	/*
+	 *	Initialise the fibs
+	 */
+	for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) 
+	{
+		fibptr->dev = dev;
+		fibptr->fib = fib;
+		fibptr->data = (void *) fibptr->fib->data;
+		fibptr->next = fibptr+1;	/* Forward chain the fibs */
+		init_MUTEX_LOCKED(&fibptr->event_wait);
+		spin_lock_init(&fibptr->event_lock);
+		fib->header.XferState = cpu_to_le32(0xffffffff);
+		fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+		fibptr->logicaladdr = (unsigned long) fibpa;
+		fib = (struct hw_fib *)((unsigned char *)fib + sizeof(struct hw_fib));
+		fibpa = fibpa + sizeof(struct hw_fib);
+	}
+	/*
+	 *	Add the fib chain to the free list
+	 */
+	dev->fibs[AAC_NUM_FIB-1].next = NULL;
+	/*
+	 *	Enable this to debug out of queue space
+	 */
+	dev->free_fib = &dev->fibs[0];
+	return 0;
+}
+
+/**
+ *	fib_alloc	-	allocate a fib
+ *	@dev: Adapter to allocate the fib for
+ *
+ *	Allocate a fib from the adapter fib pool. If the pool is empty we
+ *	wait for fibs to become free.
+ */
+ 
+struct fib * fib_alloc(struct aac_dev *dev)
+{
+	struct fib * fibptr;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&dev->fib_lock, flags);
+	fibptr = dev->free_fib;	
+	if(!fibptr)
+		BUG();
+	dev->free_fib = fibptr->next;
+	spin_unlock_irqrestore(&dev->fib_lock, flags);
+	/*
+	 *	Set the proper node type code and node byte size
+	 */
+	fibptr->type = FSAFS_NTC_FIB_CONTEXT;
+	fibptr->size = sizeof(struct fib);
+	/*
+	 *	Null out fields that depend on being zero at the start of
+	 *	each I/O
+	 */
+	fibptr->fib->header.XferState = cpu_to_le32(0);
+	fibptr->callback = NULL;
+	fibptr->callback_data = NULL;
+
+	return fibptr;
+}
+
+/**
+ *	fib_free	-	free a fib
+ *	@fibptr: fib to free up
+ *
+ *	Frees up a fib and places it on the appropriate queue
+ *	(either free or timed out)
+ */
+ 
+void fib_free(struct fib * fibptr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
+
+	if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+		aac_config.fib_timeouts++;
+		fibptr->next = fibptr->dev->timeout_fib;
+		fibptr->dev->timeout_fib = fibptr;
+	} else {
+		if (fibptr->fib->header.XferState != 0) {
+			printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 
+					 fibptr, fibptr->fib->header.XferState);
+		}
+		fibptr->next = fibptr->dev->free_fib;
+		fibptr->dev->free_fib = fibptr;
+	}	
+	spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags);
+}
+
+/**
+ *	fib_init	-	initialise a fib
+ *	@fibptr: The fib to initialize
+ *	
+ *	Set up the generic fib fields ready for use
+ */
+ 
+void fib_init(struct fib *fibptr)
+{
+	struct hw_fib *fib = fibptr->fib;
+
+	fib->header.StructType = FIB_MAGIC;
+	fib->header.Size = cpu_to_le16(sizeof(struct hw_fib));
+        fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
+	fib->header.SenderFibAddress = cpu_to_le32(0);
+	fib->header.ReceiverFibAddress = cpu_to_le32(0);
+	fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+}
+
+/**
+ *	fib_deallocate		-	deallocate a fib
+ *	@fibptr: fib to deallocate
+ *
+ *	Will deallocate and return to the free pool the FIB pointed to by the
+ *	caller.
+ */
+ 
+void fib_dealloc(struct fib * fibptr)
+{
+	struct hw_fib *fib = fibptr->fib;
+	if(fib->header.StructType != FIB_MAGIC) 
+		BUG();
+	fib->header.XferState = cpu_to_le32(0);        
+}
+
+/*
+ *	Commuication primitives define and support the queuing method we use to
+ *	support host to adapter commuication. All queue accesses happen through
+ *	these routines and are the only routines which have a knowledge of the
+ *	 how these queues are implemented.
+ */
+ 
+/**
+ *	aac_get_entry		-	get a queue entry
+ *	@dev: Adapter
+ *	@qid: Queue Number
+ *	@entry: Entry return
+ *	@index: Index return
+ *	@nonotify: notification control
+ *
+ *	With a priority the routine returns a queue entry if the queue has free entries. If the queue
+ *	is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is
+ *	returned.
+ */
+ 
+static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
+{
+	struct aac_queue * q;
+
+	/*
+	 *	All of the queues wrap when they reach the end, so we check
+	 *	to see if they have reached the end and if they have we just
+	 *	set the index back to zero. This is a wrap. You could or off
+	 *	the high bits in all updates but this is a bit faster I think.
+	 */
+
+	q = &dev->queues->queue[qid];
+	
+	*index = le32_to_cpu(*(q->headers.producer));
+		if (*index - 2 == le32_to_cpu(*(q->headers.consumer)))
+			*nonotify = 1; 
+
+	if (qid == AdapHighCmdQueue) {
+	        if (*index >= ADAP_HIGH_CMD_ENTRIES)
+        		*index = 0;
+	} else if (qid == AdapNormCmdQueue) {
+	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
+			*index = 0; /* Wrap to front of the Producer Queue. */
+	}
+	else if (qid == AdapHighRespQueue) 
+	{
+	        if (*index >= ADAP_HIGH_RESP_ENTRIES)
+			*index = 0;
+	}
+	else if (qid == AdapNormRespQueue) 
+	{
+		if (*index >= ADAP_NORM_RESP_ENTRIES) 
+			*index = 0; /* Wrap to front of the Producer Queue. */
+	}
+	else BUG();
+
+        if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
+		printk(KERN_WARNING "Queue %d full, %ld outstanding.\n",
+				qid, q->numpending);
+		return 0;
+	} else {
+	        *entry = q->base + *index;
+		return 1;
+	}
+}   
+
+/**
+ *	aac_queue_get		-	get the next free QE
+ *	@dev: Adapter
+ *	@index: Returned index
+ *	@priority: Priority of fib
+ *	@fib: Fib to associate with the queue entry
+ *	@wait: Wait if queue full
+ *	@fibptr: Driver fib object to go with fib
+ *	@nonotify: Don't notify the adapter
+ *
+ *	Gets the next free QE off the requested priorty adapter command
+ *	queue and associates the Fib with the QE. The QE represented by
+ *	index is ready to insert on the queue when this routine returns
+ *	success.
+ */
+
+static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * fib, int wait, struct fib * fibptr, unsigned long *nonotify)
+{
+	struct aac_entry * entry = NULL;
+	int map = 0;
+	struct aac_queue * q = &dev->queues->queue[qid];
+		
+	spin_lock_irqsave(q->lock, q->SavedIrql);
+	    
+	if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) 
+	{
+		/*  if no entries wait for some if caller wants to */
+        	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
+        	{
+			printk(KERN_ERR "GetEntries failed\n");
+		}
+	        /*
+	         *	Setup queue entry with a command, status and fib mapped
+	         */
+	        entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size));
+	        map = 1;
+	}
+	else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue)
+	{
+	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
+	        {
+			/* if no entries wait for some if caller wants to */
+		}
+        	/*
+        	 *	Setup queue entry with command, status and fib mapped
+        	 */
+        	entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size));
+        	entry->addr = cpu_to_le32(fib->header.SenderFibAddress);     			/* Restore adapters pointer to the FIB */
+		fib->header.ReceiverFibAddress = fib->header.SenderFibAddress;		/* Let the adapter now where to find its data */
+        	map = 0;
+	} 
+	/*
+	 *	If MapFib is true than we need to map the Fib and put pointers
+	 *	in the queue entry.
+	 */
+	if (map)
+		entry->addr = cpu_to_le32((unsigned long)(fibptr->logicaladdr));
+	return 0;
+}
+
+
+/**
+ *	aac_insert_entry	-	insert a queue entry
+ *	@dev: Adapter
+ *	@index: Index of entry to insert
+ *	@qid: Queue number
+ *	@nonotify: Suppress adapter notification
+ *
+ *	Gets the next free QE off the requested priorty adapter command
+ *	queue and associates the Fib with the QE. The QE represented by
+ *	index is ready to insert on the queue when this routine returns
+ *	success.
+ */
+ 
+static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) 
+{
+	struct aac_queue * q = &dev->queues->queue[qid];
+
+	if(q == NULL)
+		BUG();
+	*(q->headers.producer) = cpu_to_le32(index + 1);
+	spin_unlock_irqrestore(q->lock, q->SavedIrql);
+
+	if (qid == AdapHighCmdQueue ||
+	    qid == AdapNormCmdQueue ||
+	    qid == AdapHighRespQueue ||
+	    qid == AdapNormRespQueue)
+	{
+		if (!nonotify)
+			aac_adapter_notify(dev, qid);
+	}
+	else
+		printk("Suprise insert!\n");
+	return 0;
+}
+
+/*
+ *	Define the highest level of host to adapter communication routines. 
+ *	These routines will support host to adapter FS commuication. These 
+ *	routines have no knowledge of the commuication method used. This level
+ *	sends and receives FIBs. This level has no knowledge of how these FIBs
+ *	get passed back and forth.
+ */
+
+/**
+ *	fib_send	-	send a fib to the adapter
+ *	@command: Command to send
+ *	@fibptr: The fib
+ *	@size: Size of fib data area
+ *	@priority: Priority of Fib
+ *	@wait: Async/sync select
+ *	@reply: True if a reply is wanted
+ *	@callback: Called with reply
+ *	@callback_data: Passed to callback
+ *
+ *	Sends the requested FIB to the adapter and optionally will wait for a
+ *	response FIB. If the caller does not wish to wait for a response than
+ *	an event to wait on must be supplied. This event will be set when a
+ *	response FIB is received from the adapter.
+ */
+ 
+int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority, int wait, int reply, fib_callback callback, void * callback_data)
+{
+	u32 index;
+	u32 qid;
+	struct aac_dev * dev = fibptr->dev;
+	unsigned long nointr = 0;
+	struct hw_fib * fib = fibptr->fib;
+	struct aac_queue * q;
+	unsigned long flags = 0;
+
+	if (!(le32_to_cpu(fib->header.XferState) & HostOwned))
+		return -EBUSY;
+	/*
+	 *	There are 5 cases with the wait and reponse requested flags. 
+	 *	The only invalid cases are if the caller requests to wait and
+	 *	does not request a response and if the caller does not want a
+	 *	response and the Fibis not allocated from pool. If a response
+	 *	is not requesed the Fib will just be deallocaed by the DPC
+	 *	routine when the response comes back from the adapter. No
+	 *	further processing will be done besides deleting the Fib. We 
+	 *	will have a debug mode where the adapter can notify the host
+	 *	it had a problem and the host can log that fact.
+	 */
+	if (wait && !reply) {
+		return -EINVAL;
+	} else if (!wait && reply) {
+		fib->header.XferState |= cpu_to_le32(Async | ResponseExpected);
+		FIB_COUNTER_INCREMENT(aac_config.AsyncSent);
+	} else if (!wait && !reply) {
+		fib->header.XferState |= cpu_to_le32(NoResponseExpected);
+		FIB_COUNTER_INCREMENT(aac_config.NoResponseSent);
+	} else if (wait && reply) {
+		fib->header.XferState |= cpu_to_le32(ResponseExpected);
+		FIB_COUNTER_INCREMENT(aac_config.NormalSent);
+	} 
+	fib->header.SenderData = (unsigned long)fibptr;	/* for callback */
+	/*
+	 *	Set FIB state to indicate where it came from and if we want a
+	 *	response from the adapter. Also load the command from the
+	 *	caller.
+	 */
+	fib->header.SenderFibAddress = cpu_to_le32((u32)fib);
+	fib->header.Command = cpu_to_le16(command);
+	fib->header.XferState |= cpu_to_le32(SentFromHost);
+	fibptr->fib->header.Flags = 0;				/* Zero the flags field - its internal only...	 */
+	/*
+	 *	Set the size of the Fib we want to send to the adapter
+	 */
+	fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
+	if (le16_to_cpu(fib->header.Size) > le16_to_cpu(fib->header.SenderSize)) {
+		return -EMSGSIZE;
+	}                
+	/*
+	 *	Get a queue entry connect the FIB to it and send an notify
+	 *	the adapter a command is ready.
+	 */
+	if (priority == FsaHigh) {
+		fib->header.XferState |= cpu_to_le32(HighPriority);
+		qid = AdapHighCmdQueue;
+	} else {
+		fib->header.XferState |= cpu_to_le32(NormalPriority);
+		qid = AdapNormCmdQueue;
+	}
+	q = &dev->queues->queue[qid];
+
+	if(wait)
+		spin_lock_irqsave(&fibptr->event_lock, flags);
+	if(aac_queue_get( dev, &index, qid, fib, 1, fibptr, &nointr)<0)
+		return -EWOULDBLOCK;
+	dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
+	dprintk((KERN_DEBUG "Fib contents:.\n"));
+	dprintk((KERN_DEBUG "  Command =               %d.\n", fib->header.Command));
+	dprintk((KERN_DEBUG "  XferState  =            %x.\n", fib->header.XferState));
+	/*
+	 *	Fill in the Callback and CallbackContext if we are not
+	 *	going to wait.
+	 */
+	if (!wait) {
+		fibptr->callback = callback;
+		fibptr->callback_data = callback_data;
+	}
+	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
+	list_add_tail(&fibptr->queue, &q->pendingq);
+	q->numpending++;
+
+	fibptr->done = 0;
+
+	if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0)
+		return -EWOULDBLOCK;
+	/*
+	 *	If the caller wanted us to wait for response wait now. 
+	 */
+    
+	if (wait) {
+		spin_unlock_irqrestore(&fibptr->event_lock, flags);
+		down(&fibptr->event_wait);
+		if(fibptr->done == 0)
+			BUG();
+			
+		if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
+			return -ETIMEDOUT;
+		else
+			return 0;
+	}
+	/*
+	 *	If the user does not want a response than return success otherwise
+	 *	return pending
+	 */
+	if (reply)
+		return -EINPROGRESS;
+	else
+		return 0;
+}
+
+/** 
+ *	aac_consumer_get	-	get the top of the queue
+ *	@dev: Adapter
+ *	@q: Queue
+ *	@entry: Return entry
+ *
+ *	Will return a pointer to the entry on the top of the queue requested that
+ * 	we are a consumer of, and return the address of the queue entry. It does
+ *	not change the state of the queue. 
+ */
+
+int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry)
+{
+	u32 index;
+	int status;
+
+	if (*q->headers.producer == *q->headers.consumer) {
+		status = 0;
+	} else {
+		/*
+		 *	The consumer index must be wrapped if we have reached
+		 *	the end of the queue, else we just use the entry
+		 *	pointed to by the header index
+		 */
+		if (le32_to_cpu(*q->headers.consumer) >= q->entries) 
+			index = 0;		
+		else
+		        index = le32_to_cpu(*q->headers.consumer);
+		*entry = q->base + index;
+		status = 1;
+	}
+	return(status);
+}
+
+int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q)
+{
+	return (*q->headers.producer != *q->headers.consumer);
+}
+
+
+/**
+ *	aac_consumer_free	-	free consumer entry
+ *	@dev: Adapter
+ *	@q: Queue
+ *	@qid: Queue ident
+ *
+ *	Frees up the current top of the queue we are a consumer of. If the
+ *	queue was full notify the producer that the queue is no longer full.
+ */
+
+void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
+{
+	int wasfull = 0;
+	u32 notify;
+
+	if (*q->headers.producer+1 == *q->headers.consumer)
+		wasfull = 1;
+        
+	if (le32_to_cpu(*q->headers.consumer) >= q->entries)
+		*q->headers.consumer = cpu_to_le32(1);
+	else
+		*q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
+        
+	if (wasfull) {
+		switch (qid) {
+
+		case HostNormCmdQueue:
+			notify = HostNormCmdNotFull;
+			break;
+		case HostHighCmdQueue:
+			notify = HostHighCmdNotFull;
+			break;
+		case HostNormRespQueue:
+			notify = HostNormRespNotFull;
+			break;
+		case HostHighRespQueue:
+			notify = HostHighRespNotFull;
+			break;
+		default:
+			BUG();
+			return;
+		}
+		aac_adapter_notify(dev, notify);
+	}
+}        
+
+/**
+ *	fib_adapter_complete	-	complete adapter issued fib
+ *	@fibptr: fib to complete
+ *	@size: size of fib
+ *
+ *	Will do all necessary work to complete a FIB that was sent from
+ *	the adapter.
+ */
+
+int fib_adapter_complete(struct fib * fibptr, unsigned short size)
+{
+	struct hw_fib * fib = fibptr->fib;
+	struct aac_dev * dev = fibptr->dev;
+	unsigned long nointr = 0;
+
+	if (le32_to_cpu(fib->header.XferState) == 0)
+        	return 0;
+	/*
+	 *	If we plan to do anything check the structure type first.
+	 */ 
+	if ( fib->header.StructType != FIB_MAGIC ) {
+        	return -EINVAL;
+	}
+	/*
+	 *	This block handles the case where the adapter had sent us a
+	 *	command and we have finished processing the command. We
+	 *	call completeFib when we are done processing the command 
+	 *	and want to send a response back to the adapter. This will 
+	 *	send the completed cdb to the adapter.
+	 */
+	if (fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
+	        fib->header.XferState |= cpu_to_le32(HostProcessed);
+	        if (fib->header.XferState & cpu_to_le32(HighPriority)) {
+        		u32 index;
+       			if (size) 
+			{
+				size += sizeof(struct aac_fibhdr);
+				if (size > le16_to_cpu(fib->header.SenderSize))
+					return -EMSGSIZE;
+				fib->header.Size = cpu_to_le16(size);
+			}
+			if(aac_queue_get(dev, &index, AdapHighRespQueue, fib, 1, NULL, &nointr) < 0) {
+				return -EWOULDBLOCK;
+			}
+			if (aac_insert_entry(dev, index, AdapHighRespQueue,  (nointr & (int)aac_config.irq_mod)) != 0) {
+			}
+		}
+		else if (fib->header.XferState & NormalPriority) 
+		{
+			u32 index;
+
+			if (size) {
+				size += sizeof(struct aac_fibhdr);
+				if (size > le16_to_cpu(fib->header.SenderSize)) 
+					return -EMSGSIZE;
+				fib->header.Size = cpu_to_le16(size);
+			}
+			if (aac_queue_get(dev, &index, AdapNormRespQueue, fib, 1, NULL, &nointr) < 0) 
+				return -EWOULDBLOCK;
+			if (aac_insert_entry(dev, index, AdapNormRespQueue, 
+				(nointr & (int)aac_config.irq_mod)) != 0) 
+			{
+			}
+		}
+	}
+	else 
+	{
+        	printk(KERN_WARNING "fib_complete: Unknown xferstate detected.\n");
+        	BUG();
+	}   
+	return 0;
+}
+
+/**
+ *	fib_complete	-	fib completion handler
+ *	@fib: FIB to complete
+ *
+ *	Will do all necessary work to complete a FIB.
+ */
+ 
+int fib_complete(struct fib * fibptr)
+{
+	struct hw_fib * fib = fibptr->fib;
+
+	/*
+	 *	Check for a fib which has already been completed
+	 */
+
+	if (fib->header.XferState == cpu_to_le32(0))
+        	return 0;
+	/*
+	 *	If we plan to do anything check the structure type first.
+	 */ 
+
+	if (fib->header.StructType != FIB_MAGIC)
+	        return -EINVAL;
+	/*
+	 *	This block completes a cdb which orginated on the host and we 
+	 *	just need to deallocate the cdb or reinit it. At this point the
+	 *	command is complete that we had sent to the adapter and this
+	 *	cdb could be reused.
+	 */
+	if((fib->header.XferState & cpu_to_le32(SentFromHost)) &&
+		(fib->header.XferState & cpu_to_le32(AdapterProcessed)))
+	{
+		fib_dealloc(fibptr);
+	}
+	else if(fib->header.XferState & cpu_to_le32(SentFromHost))
+	{
+		/*
+		 *	This handles the case when the host has aborted the I/O
+		 *	to the adapter because the adapter is not responding
+		 */
+		fib_dealloc(fibptr);
+	} else if(fib->header.XferState & cpu_to_le32(HostOwned)) {
+		fib_dealloc(fibptr);
+	} else {
+		BUG();
+	}   
+	return 0;
+}
+
+/**
+ *	aac_printf	-	handle printf from firmware
+ *	@dev: Adapter
+ *	@val: Message info
+ *
+ *	Print a message passed to us by the controller firmware on the
+ *	Adaptec board
+ */
+
+void aac_printf(struct aac_dev *dev, u32 val)
+{
+	int length = val & 0xffff;
+	int level = (val >> 16) & 0xffff;
+	char *cp = dev->printfbuf;
+	
+	/*
+	 *	The size of the printfbuf is set in port.c
+	 *	There is no variable or define for it
+	 */
+	if (length > 255)
+		length = 255;
+	if (cp[length] != 0)
+		cp[length] = 0;
+	if (level == LOG_HIGH_ERROR)
+		printk(KERN_WARNING "aacraid:%s.\n", cp);
+	else
+		printk(KERN_INFO "aacraid:%s.\n", cp);
+	memset(cp, 0,  256);
+}
+
+
+/**
+ *	aac_handle_aif		-	Handle a message from the firmware
+ *	@dev: Which adapter this fib is from
+ *	@fibptr: Pointer to fibptr from adapter
+ *
+ *	This routine handles a driver notify fib from the adapter and
+ *	dispatches it to the appropriate routine for handling.
+ */
+
+static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+{
+	struct hw_fib * fib = fibptr->fib;
+	/*
+	 * Set the status of this FIB to be Invalid parameter.
+	 *
+	 *	*(u32 *)fib->data = ST_INVAL;
+	 */
+	*(u32 *)fib->data = cpu_to_le32(ST_OK);
+	fib_adapter_complete(fibptr, sizeof(u32));
+}
+
+/**
+ *	aac_command_thread	-	command processing thread
+ *	@dev: Adapter to monitor
+ *
+ *	Waits on the commandready event in it's queue. When the event gets set
+ *	it will pull FIBs off it's queue. It will continue to pull FIBs off
+ *	until the queue is empty. When the queue is empty it will wait for
+ *	more FIBs.
+ */
+ 
+int aac_command_thread(struct aac_dev * dev)
+{
+	struct hw_fib *fib, *newfib;
+	struct fib fibptr; /* for error logging */
+	struct aac_queue_block *queues = dev->queues;
+	struct aac_fib_context *fibctx;
+	unsigned long flags;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 *	We can only have one thread per adapter for AIF's.
+	 */
+	if (dev->aif_thread)
+		return -EINVAL;
+	/*
+	 *	Set up the name that will appear in 'ps'
+	 *	stored in  task_struct.comm[16].
+	 */
+	sprintf(current->comm, "aacraid");
+	daemonize();
+	/*
+	 *	Let the DPC know it has a place to send the AIF's to.
+	 */
+	dev->aif_thread = 1;
+	memset(&fibptr, 0, sizeof(struct fib));
+	add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while(1) 
+	{
+		spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+		while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
+			struct list_head *entry;
+			struct aac_aifcmd * aifcmd;
+
+			set_current_state(TASK_RUNNING);
+		
+			entry = queues->queue[HostNormCmdQueue].cmdq.next;
+			list_del(entry);
+			
+			spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+			fib = list_entry(entry, struct hw_fib, header.FibLinks);
+			/*
+			 *	We will process the FIB here or pass it to a 
+			 *	worker thread that is TBD. We Really can't 
+			 *	do anything at this point since we don't have
+			 *	anything defined for this thread to do.
+			 */
+			memset(&fibptr, 0, sizeof(struct fib));
+			fibptr.type = FSAFS_NTC_FIB_CONTEXT;
+			fibptr.size = sizeof( struct fib );
+			fibptr.fib = fib;
+			fibptr.data = fib->data;
+			fibptr.dev = dev;
+			/*
+			 *	We only handle AifRequest fibs from the adapter.
+			 */
+			aifcmd = (struct aac_aifcmd *) fib->data;
+			if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) {
+				aac_handle_aif(dev, &fibptr);
+			} else {
+				/* The u32 here is important and intended. We are using
+				   32bit wrapping time to fit the adapter field */
+				   
+				u32 time_now, time_last;
+				unsigned long flagv;
+				
+				time_now = jiffies/HZ;
+
+				spin_lock_irqsave(&dev->fib_lock, flagv);
+				entry = dev->fib_list.next;
+				/*
+				 * For each Context that is on the 
+				 * fibctxList, make a copy of the
+				 * fib, and then set the event to wake up the
+				 * thread that is waiting for it.
+				 */
+				while (entry != &dev->fib_list) {
+					/*
+					 * Extract the fibctx
+					 */
+					fibctx = list_entry(entry, struct aac_fib_context, next);
+					/*
+					 * Check if the queue is getting
+					 * backlogged
+					 */
+					if (fibctx->count > 20)
+					{
+						time_last = fibctx->jiffies;
+						/*
+						 * Has it been > 2 minutes 
+						 * since the last read off
+						 * the queue?
+						 */
+						if ((time_now - time_last) > 120) {
+							entry = entry->next;
+							aac_close_fib_context(dev, fibctx);
+							continue;
+						}
+					}
+					/*
+					 * Warning: no sleep allowed while
+					 * holding spinlock
+					 */
+					newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+					if (newfib) {
+						/*
+						 * Make the copy of the FIB
+						 */
+						memcpy(newfib, fib, sizeof(struct hw_fib));
+						/*
+						 * Put the FIB onto the
+						 * fibctx's fibs
+						 */
+						list_add_tail(&newfib->header.FibLinks, &fibctx->fibs);
+						fibctx->count++;
+						/* 
+						 * Set the event to wake up the
+						 * thread that will waiting.
+						 */
+						up(&fibctx->wait_sem);
+					} else {
+						printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
+					}
+					entry = entry->next;
+				}
+				/*
+				 *	Set the status of this FIB
+				 */
+				*(u32 *)fib->data = cpu_to_le32(ST_OK);
+				fib_adapter_complete(&fibptr, sizeof(u32));
+				spin_unlock_irqrestore(&dev->fib_lock, flagv);
+			}
+			spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+		}
+		/*
+		 *	There are no more AIF's
+		 */
+		spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+		schedule();
+
+		if(signal_pending(current))
+			break;
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	dev->aif_thread = 0;
+	complete_and_exit(&dev->aif_completion, 0);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/dpcsup.c linux/drivers/scsi/aacraid/dpcsup.c
--- linux-2.4.16/drivers/scsi/aacraid/dpcsup.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/dpcsup.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,201 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  dpcsup.c
+ *
+ * Abstract: All DPC processing routines for the cyclone board occur here.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/blk.h>
+#include <asm/semaphore.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+/**
+ *	aac_response_normal	-	Handle command replies
+ *	@q: Queue to read from
+ *
+ *	This DPC routine will be run when the adapter interrupts us to let us
+ *	know there is a response on our normal priority queue. We will pull off
+ *	all QE there are and wake up all the waiters before exiting. We will
+ *	take a spinlock out on the queue before operating on it.
+ */
+
+unsigned int aac_response_normal(struct aac_queue * q)
+{
+	struct aac_dev * dev = q->dev;
+	struct aac_entry *entry;
+	struct hw_fib * fib;
+	struct fib * fibctx;
+	int consumed = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->lock, flags);	
+
+	/*
+	 *	Keep pulling response QEs off the response queue and waking
+	 *	up the waiters until there are no more QEs. We then return
+	 *	back to the system. If no response was requesed we just
+	 *	deallocate the Fib here and continue.
+	 */
+	while(aac_consumer_get(dev, q, &entry))
+	{
+		int fast;
+
+		fast = (int) (entry->addr & 0x01);
+		fib = (struct hw_fib *) (entry->addr & ~0x01);
+		aac_consumer_free(dev, q, HostNormRespQueue);
+		fibctx = (struct fib *)fib->header.SenderData;
+		/*
+		 *	Remove this fibctx from the Outstanding I/O queue.
+		 *	But only if it has not already been timed out.
+		 *
+		 *	If the fib has been timed out already, then just 
+		 *	continue. The caller has already been notified that
+		 *	the fib timed out.
+		 */
+		if (!(fibctx->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+			list_del(&fibctx->queue);
+			dev->queues->queue[AdapNormCmdQueue].numpending--;
+		} else {
+			printk(KERN_WARNING "aacraid: FIB timeout.\n");
+			continue;
+		}
+		spin_unlock_irqrestore(q->lock, flags);
+
+		if (fast) {
+			/*
+			 *	Doctor the fib
+			 */
+			*(u32 *)fib->data = cpu_to_le32(ST_OK);
+			fib->header.XferState |= cpu_to_le32(AdapterProcessed);
+		}
+
+		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
+
+		if (fib->header.Command == cpu_to_le16(NuFileSystem))
+		{
+			u32 *pstatus = (u32 *)fib->data;
+			if (*pstatus & cpu_to_le32(0xffff0000))
+				*pstatus = cpu_to_le32(ST_OK);
+		}
+		if (fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
+		{
+	        	if (fib->header.XferState & cpu_to_le32(NoResponseExpected))
+				FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
+			else 
+				FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
+			/*
+			 *	NOTE:  we cannot touch the fibctx after this
+			 *	    call, because it may have been deallocated.
+			 */
+			fibctx->callback(fibctx->callback_data, fibctx);
+		} else {
+			unsigned long flagv;
+			spin_lock_irqsave(&fibctx->event_lock, flagv);
+			fibctx->done = 1;
+			up(&fibctx->event_wait);
+			spin_unlock_irqrestore(&fibctx->event_lock, flagv);
+			FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+		}
+		consumed++;
+		spin_lock_irqsave(q->lock, flags);
+	}
+
+	if (consumed > aac_config.peak_fibs)
+		aac_config.peak_fibs = consumed;
+	if (consumed == 0) 
+		aac_config.zero_fibs++;
+
+	spin_unlock_irqrestore(q->lock, flags);
+	return 0;
+}
+
+
+/**
+ *	aac_command_normal	-	handle commands
+ *	@q: queue to process
+ *
+ *	This DPC routine will be queued when the adapter interrupts us to 
+ *	let us know there is a command on our normal priority queue. We will 
+ *	pull off all QE there are and wake up all the waiters before exiting.
+ *	We will take a spinlock out on the queue before operating on it.
+ */
+ 
+unsigned int aac_command_normal(struct aac_queue *q)
+{
+	struct aac_dev * dev = q->dev;
+	struct aac_entry *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->lock, flags);
+
+	/*
+	 *	Keep pulling response QEs off the response queue and waking
+	 *	up the waiters until there are no more QEs. We then return
+	 *	back to the system.
+	 */
+	while(aac_consumer_get(dev, q, &entry))
+	{
+		struct hw_fib * fib;
+		fib = (struct hw_fib *)entry->addr;
+
+		if (dev->aif_thread) {
+		        list_add_tail(&fib->header.FibLinks, &q->cmdq);
+	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
+		        wake_up_interruptible(&q->cmdready);
+		} else {
+			struct fib fibctx;
+	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
+			spin_unlock_irqrestore(q->lock, flags);
+			memset(&fibctx, 0, sizeof(struct fib));
+			fibctx.type = FSAFS_NTC_FIB_CONTEXT;
+			fibctx.size = sizeof(struct fib);
+			fibctx.fib = fib;
+			fibctx.data = fib->data;
+			fibctx.dev = dev;
+			/*
+			 *	Set the status of this FIB
+			 */
+			*(u32 *)fib->data = cpu_to_le32(ST_OK);
+			fib_adapter_complete(&fibctx, sizeof(u32));
+			spin_lock_irqsave(q->lock, flags);
+		}		
+	}
+	spin_unlock_irqrestore(q->lock, flags);
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/linit.c linux/drivers/scsi/aacraid/linit.c
--- linux-2.4.16/drivers/scsi/aacraid/linit.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/linit.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,691 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   linit.c
+ *
+ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
+ *				
+ *	Provides the following driver entry points:
+ *		aac_detect()
+ *		aac_release()
+ *		aac_queuecommand()
+ *		aac_resetcommand()
+ *		aac_biosparm()
+ *	
+ */
+
+#define AAC_DRIVER_VERSION		"0.9.9ac2-rel"
+#define AAC_DRIVER_BUILD_DATE		__DATE__
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+#include "sd.h"
+
+#define AAC_DRIVERNAME	"aacraid"
+
+MODULE_AUTHOR("Red Hat Inc and Adaptec OEM RAID Solutions");
+MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, and HP NetRAID-4M devices.  http://domsch.com/linux/");
+MODULE_LICENSE("GPL");
+
+struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS];
+
+static unsigned aac_count = 0;
+static int aac_cfg_major = -1;
+static int single_command_done = 0;
+
+/*
+ * Because of the way Linux names scsi devices, the order in this table has
+ * become important.  Check for on-board Raid first, add-in cards second.
+ */
+
+/* FIXME static */struct aac_driver_ident aac_drivers[] = {
+	{ 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 2/Si */
+	{ 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
+	{ 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
+	{ 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        " }, /* Dell PERC2 "Quad Channel" */
+	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   " }, /* Adaptec 5400S */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID-4M      " }  /* HP NetRAID-4M */
+};
+
+#define NUM_AACTYPES	(sizeof(aac_drivers) / sizeof(struct aac_driver_ident))
+static int num_aacdrivers = NUM_AACTYPES;
+
+static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+static int aac_cfg_open(struct inode * inode, struct file * file);
+static int aac_cfg_release(struct inode * inode,struct file * file);
+
+static struct file_operations aac_cfg_fops = {
+	owner: THIS_MODULE,
+	ioctl: aac_cfg_ioctl,
+	open: aac_cfg_open,
+	release: aac_cfg_release
+};
+
+static int aac_detect(Scsi_Host_Template *);
+static int aac_release(struct Scsi_Host *);
+static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *));
+static int aac_command(Scsi_Cmnd *);
+static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr);
+static int aac_resetcommand(Scsi_Cmnd *, unsigned int);
+static int aac_biosparm(Scsi_Disk *, kdev_t, int *);
+static int aac_procinfo(char *, char **, off_t, int, int, int);
+static int aac_ioctl(Scsi_Device *, int, void *);
+
+static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *);
+
+/**
+ *	aac_detect	-	Probe for aacraid cards
+ *	@template: SCSI driver template
+ *
+ *	Probe for AAC Host Adapters initialize, register, and report the 
+ *	configuration of each AAC Host Adapter found.
+ *	Returns the number of adapters successfully initialized and 
+ *	registered.
+ *	Initializes all data necessary for this particular SCSI driver.
+ *	Notes:
+ *	The detect routine must not call any of the mid level functions 
+ *	to queue commands because things are not guaranteed to be set 
+ *	up yet. The detect routine can send commands to the host adapter 
+ *	as long as the program control will not be passed to scsi.c in 
+ *	the processing of the command. Note especially that 
+ *	scsi_malloc/scsi_free must not be called.
+ *
+ */
+ 
+static int aac_detect(Scsi_Host_Template *template)
+{
+	int index;
+	int container;
+	u16 vendor_id, device_id;
+	struct Scsi_Host *host_ptr;
+	struct pci_dev *dev = NULL;
+	struct aac_dev *aac;
+	struct fsa_scsi_hba *fsa_dev_ptr;
+	char *name = NULL;
+	
+	printk(KERN_INFO "Red Hat/Adaptec aacraid driver, %s\n", AAC_DRIVER_BUILD_DATE);
+
+	/* setting up the proc directory structure */
+	template->proc_name = "aacraid";
+
+	for( index = 0; index != num_aacdrivers; index++ )
+	{
+		device_id = aac_drivers[index].device;
+		vendor_id = aac_drivers[index].vendor;
+		name = aac_drivers[index].name;
+		dprintk((KERN_DEBUG "Checking %s %x/%x/%x/%x.\n", 
+			name, vendor_id, device_id,
+			aac_drivers[index].subsystem_vendor,
+			aac_drivers[index].subsystem_device));
+
+		dev = NULL;
+		while((dev = pci_find_device(vendor_id, device_id, dev)))
+		{
+			if (pci_enable_device(dev))
+				continue;
+			pci_set_master(dev);
+			pci_set_dma_mask(dev, 0xFFFFFFFFULL);
+
+			if((dev->subsystem_vendor != aac_drivers[index].subsystem_vendor) || 
+			   (dev->subsystem_device != aac_drivers[index].subsystem_device))
+					continue;
+
+			dprintk((KERN_DEBUG "%s device detected.\n", name));
+			dprintk((KERN_DEBUG "%x/%x/%x/%x.\n", vendor_id, device_id, 
+				aac_drivers[index].subsystem_vendor, aac_drivers[index].subsystem_device));
+			/* Increment the host adapter count */
+			aac_count++;
+			/*
+			 * scsi_register() allocates memory for a Scsi_Hosts structure and
+			 * links it into the linked list of host adapters. This linked list
+			 * contains the data for all possible <supported> scsi hosts.
+			 * This is similar to the Scsi_Host_Template, except that we have
+			 * one entry for each actual physical host adapter on the system,
+			 * stored as a linked list. If there are two AAC boards, then we
+			 * will need to make two Scsi_Host entries, but there will be only
+			 * one Scsi_Host_Template entry. The second argument to scsi_register()
+			 * specifies the size of the extra memory we want to hold any device 
+			 * specific information.
+			 */
+			host_ptr = scsi_register( template, sizeof(struct aac_dev) );
+			/* 
+			 * These three parameters can be used to allow for wide SCSI 
+			 * and for host adapters that support multiple buses.
+			 */
+			host_ptr->max_id = 17;
+			host_ptr->max_lun = 8;
+			host_ptr->max_channel = 1;
+			host_ptr->irq = dev->irq;		/* Adapter IRQ number */
+			/* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */
+			host_ptr->base = dev->resource[0].start;
+			scsi_set_pci_device(host_ptr, dev);
+			dprintk((KERN_DEBUG "Device base address = 0x%lx [0x%lx].\n", host_ptr->base, dev->resource[0].start));
+			dprintk((KERN_DEBUG "Device irq = 0x%x.\n", dev->irq));
+			/*
+			 * The unique_id field is a unique identifier that must
+			 * be assigned so that we have some way of identifying
+			 * each host adapter properly and uniquely. For hosts 
+			 * that do not support more than one card in the
+			 * system, this does not need to be set. It is
+			 * initialized to zero in scsi_register(). This is the 
+			 * value returned as aac->id.
+			 */
+			host_ptr->unique_id = aac_count - 1;
+			/*
+			 *	This function is called after the device list has
+			 *	been built to find the tagged queueing depth 
+			 *	supported for each device.
+			 */
+			host_ptr->select_queue_depths = aac_queuedepth;
+			aac = (struct aac_dev *)host_ptr->hostdata;
+			/* attach a pointer back to Scsi_Host */
+			aac->scsi_host_ptr = host_ptr;	
+			aac->pdev = dev;
+			aac->cardtype =  index;
+			aac->name = aac->scsi_host_ptr->hostt->name;
+			aac->id = aac->scsi_host_ptr->unique_id;
+			/* Initialize the ordinal number of the device to -1 */
+			fsa_dev_ptr = &(aac->fsa_dev);
+			for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ )
+				fsa_dev_ptr->devno[container] = -1;
+
+			dprintk((KERN_DEBUG "Initializing Hardware...\n"));
+			if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0)
+			{
+				/* device initialization failed */
+				printk(KERN_WARNING "aacraid: device initialization failed.\n");
+				scsi_unregister(host_ptr);
+				aac_count--;
+			} 
+			else
+			{
+				dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id));
+				aac_get_containers(aac);
+				aac_devices[aac_count-1] = aac;
+			}
+		}
+	}
+
+	if( aac_count ){
+		if((aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops))<0)
+			printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n");
+	}
+
+	template->present = aac_count; /* # of cards of this type found */
+	return aac_count;
+}
+
+/**
+ *	aac_release	-	release SCSI host resources
+ *	@host_ptr: SCSI host to clean up
+ *
+ *	Release all resources previously acquired to support a specific Host 
+ *	Adapter and unregister the AAC Host Adapter.
+ *
+ *	BUGS: Does not wait for the thread it kills to die.
+ */
+
+static int aac_release(struct Scsi_Host *host_ptr)
+{
+	struct aac_dev *dev;
+	dprintk((KERN_DEBUG "aac_release.\n"));
+	dev = (struct aac_dev *)host_ptr->hostdata;
+	/*
+	 *	kill any threads we started
+	 */
+	kill_proc(dev->thread_pid, SIGKILL, 0);
+	wait_for_completion(&dev->aif_completion);
+	/*
+	 *	Call the comm layer to detach from this adapter
+	 */
+	aac_detach(dev);
+	/* Check free orderings... */
+	/* remove interrupt binding */
+	free_irq(host_ptr->irq, dev);
+	iounmap((void * )dev->regs.sa);
+	/* unregister adapter */
+	scsi_unregister(host_ptr);
+	/*
+	 *	FIXME: This assumes no hot plugging is going on...
+	 */
+	if( aac_cfg_major >= 0 )
+	{
+		unregister_chrdev(aac_cfg_major, "aac");
+		aac_cfg_major = -1;
+	}
+	return 0;
+}
+
+/**
+ *	aac_queuecommand	-	queue a SCSI command
+ *	@scsi_cmnd_ptr:	SCSI command to queue
+ *	@CompletionRoutine: Function to call on command completion
+ *
+ *	Queues a command for execution by the associated Host Adapter.
+ */ 
+
+static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*CompletionRoutine)(Scsi_Cmnd *))
+{
+	int ret;
+
+	scsi_cmnd_ptr->scsi_done = CompletionRoutine;
+	/*
+	 *	aac_scsi_cmd() handles command processing, setting the 
+	 *	result code and calling completion routine. 
+	 */
+	if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0)
+		dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n"));
+	return ret;
+} 
+
+
+/**
+ *	aac_done	-	Callback function for a non-queued command.
+ *	@scsi_cmnd_ptr:	SCSI command block to wait for
+ *
+ *	Sets single_command done to 1. This lets aac_command complete. 
+ *	This function is obsolete.
+ *
+ *	Bugs: Doesn't actually work properly with multiple controllers
+ */
+ 
+static void aac_done(Scsi_Cmnd * scsi_cmnd_ptr) 
+{
+	single_command_done = 1;
+}
+
+/**
+ *	aac_command	-	synchronous SCSI command execution
+ *	@scsi_cmnd_ptr:	SCSI command to issue
+ *
+ *	Accepts a single command for execution by the associated Host Adapter.
+ *	Waits until it completes an then returns an int where:
+ *		Byte 0 = SCSI status code
+ *		Byte 1 = SCSI 1 byte message
+ *		Byte 2 = host error return
+ *		Byte 3 = mid level error return
+ */
+ 
+static int aac_command(Scsi_Cmnd *scsi_cmnd_ptr )
+{
+	scsi_cmnd_ptr->scsi_done = aac_done;
+	dprintk((KERN_DEBUG "aac_command.\n"));
+
+	/*
+	 *	aac_scsi_cmd() handles command processing, setting the 
+	 *	result code and calling completion routine.
+	 */
+	single_command_done = 0;
+	aac_scsi_cmd(scsi_cmnd_ptr);
+	while(!single_command_done)
+		rmb();
+	return scsi_cmnd_ptr->result;
+} 
+
+/**
+ *	aac_abortcommand	-	Abort command if possible.
+ *	@scsi_cmnd_ptr:	SCSI command block to abort
+ *
+ *	Called when the midlayer wishes to abort a command. We don't support
+ *	this facility, and our firmware looks after life for us. We just
+ *	report the command as busy. 
+ */
+ 
+static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr )
+{
+	return SCSI_ABORT_BUSY;
+}
+
+/**
+ *	aac_resetcommand	-	Reset command handling
+ *	@scsi_cmnd_ptr:	SCSI command block causing the reset
+ *	@reset_flags: Reset hints from the midlayer code
+ *
+ *	Issue a reset of a SCSI command. We are ourselves not truely a SCSI
+ *	controller and our firmware will do the work for us anyway. Thus this
+ *	is a no-op. We just return SCSI_RESET_PUNT
+ */
+ 
+static int aac_resetcommand(struct scsi_cmnd *scsi_cmnd_ptr, unsigned int reset_flags )
+{
+	return SCSI_RESET_PUNT;
+}
+
+/**
+ *	aac_driverinfo		-	Returns the host adapter name
+ *	@host_ptr:	Scsi host to report on
+ *
+ *	Returns a static string describing the device in question
+ */
+
+const char *aac_driverinfo(struct Scsi_Host *host_ptr)
+{
+	struct aac_dev *dev = (struct aac_dev *)host_ptr->hostdata;
+	return aac_drivers[dev->cardtype].name;
+}
+
+/**
+ *	aac_biosparm	-	return BIOS parameters for disk
+ *	@disk: SCSI disk object to process
+ *	@device: kdev_t of the disk in question
+ *	@geom: geometry block to fill in
+ *
+ *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
+ *	The default disk geometry is 64 heads, 32 sectors, and the appropriate 
+ *	number of cylinders so as not to exceed drive capacity.  In order for 
+ *	disks equal to or larger than 1 GB to be addressable by the BIOS
+ *	without exceeding the BIOS limitation of 1024 cylinders, Extended 
+ *	Translation should be enabled.   With Extended Translation enabled, 
+ *	drives between 1 GB inclusive and 2 GB exclusive are given a disk 
+ *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
+ *	are given a disk geometry of 255 heads and 63 sectors.  However, if 
+ *	the BIOS detects that the Extended Translation setting does not match 
+ *	the geometry in the partition table, then the translation inferred 
+ *	from the partition table will be used by the BIOS, and a warning may 
+ *	be displayed.
+ */
+ 
+static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom)
+{
+	struct diskparm *param = (struct diskparm *)geom;
+	struct buffer_head * buf;
+
+	dprintk((KERN_DEBUG "aac_biosparm.\n"));
+
+	/*
+	 *	Assuming extended translation is enabled - #REVISIT#
+	 */
+	if( disk->capacity >= 2 * 1024 * 1024 ) /* 1 GB in 512 byte sectors */
+	{
+		if( disk->capacity >= 4 * 1024 * 1024 ) /* 2 GB in 512 byte sectors */
+		{
+			param->heads = 255;
+			param->sectors = 63;
+		}
+		else
+		{
+			param->heads = 128;
+			param->sectors = 32;
+		}
+	}
+	else
+	{
+		param->heads = 64;
+		param->sectors = 32;
+	}
+
+	param->cylinders = disk->capacity/(param->heads * param->sectors);
+
+	/*
+	 *	Read the first 1024 bytes from the disk device
+	 */
+
+	buf = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev));
+	if(buf == NULL)
+		return 0;
+	/* 
+	 *	If the boot sector partition table is valid, search for a partition 
+	 *	table entry whose end_head matches one of the standard geometry 
+	 *	translations ( 64/32, 128/32, 255/63 ).
+	 */
+	 
+	if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55))
+	{
+		struct partition *first = (struct partition * )(buf->b_data + 0x1be);
+		struct partition *entry = first;
+		int saved_cylinders = param->cylinders;
+		int num;
+		unsigned char end_head, end_sec;
+
+		for(num = 0; num < 4; num++)
+		{
+			end_head = entry->end_head;
+			end_sec = entry->end_sector & 0x3f;
+
+			if(end_head == 63)
+			{
+				param->heads = 64;
+				param->sectors = 32;
+				break;
+			}
+			else if(end_head == 127)
+			{
+				param->heads = 128;
+				param->sectors = 32;
+				break;
+			}
+			else if(end_head == 254) 
+			{
+				param->heads = 255;
+				param->sectors = 63;
+				break;
+			}
+			entry++;
+		}
+
+		if(num == 4)
+		{
+			end_head = first->end_head;
+			end_sec = first->end_sector & 0x3f;
+		}
+
+		param->cylinders = disk->capacity / (param->heads * param->sectors);
+
+		if(num < 4 && end_sec == param->sectors)
+		{
+			if(param->cylinders != saved_cylinders)
+				dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n",
+					param->heads, param->sectors, num));
+		}
+		else if(end_head > 0 || end_sec > 0)
+		{
+			dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n",
+				end_head + 1, end_sec, num));
+			dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n",
+					param->heads, param->sectors));
+		}
+	}
+	brelse(buf);
+	return 0;
+}
+
+/**
+ *	aac_queuedepth		-	compute queue depths
+ *	@host:	SCSI host in question
+ *	@dev:	SCSI device we are considering
+ *
+ *	Selects queue depths for each target device based on the host adapter's
+ *	total capacity and the queue depth supported by the target device.
+ *	A queue depth of one automatically disables tagged queueing.
+ */
+
+static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev )
+{
+	Scsi_Device * dptr;
+
+	dprintk((KERN_DEBUG "aac_queuedepth.\n"));
+	dprintk((KERN_DEBUG "Device #   Q Depth   Online\n"));
+	dprintk((KERN_DEBUG "---------------------------\n"));
+	for(dptr = dev; dptr != NULL; dptr = dptr->next)
+	{
+		if(dptr->host == host)
+		{
+			dptr->queue_depth = 10;		
+			dprintk((KERN_DEBUG "  %2d         %d        %d\n", 
+				dptr->id, dptr->queue_depth, dptr->online));
+		}
+	}
+}
+
+/*------------------------------------------------------------------------------
+	aac_ioctl()
+
+		Handle SCSI ioctls
+ *----------------------------------------------------------------------------*/
+static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg)
+/*----------------------------------------------------------------------------*/
+{
+	struct aac_dev *dev;
+	dprintk((KERN_DEBUG "aac_ioctl.\n"));
+	dev = (struct aac_dev *)scsi_dev_ptr->host->hostdata;
+	return aac_do_ioctl(dev, cmd, arg);
+}
+
+/**
+ *	aac_cfg_open		-	open a configuration file
+ *	@inode: inode being opened
+ *	@file: file handle attached
+ *
+ *	Called when the configuration device is opened. Does the needed
+ *	set up on the handle and then returns
+ *
+ *	Bugs: This needs extending to check a given adapter is present
+ *	so we can support hot plugging, and to ref count adapters.
+ */
+
+static int aac_cfg_open(struct inode * inode, struct file * file )
+{
+	unsigned minor_number = MINOR(inode->i_rdev);
+	if(minor_number >= aac_count)
+		return -ENODEV;
+	return 0;
+}
+
+/**
+ *	aac_cfg_release		-	close down an AAC config device
+ *	@inode: inode of configuration file
+ *	@file: file handle of configuration file
+ *	
+ *	Called when the last close of the configuration file handle
+ *	is performed.
+ */
+ 
+static int aac_cfg_release(struct inode * inode, struct file * file )
+{
+	return 0;
+}
+
+/**
+ *	aac_cfg_ioctl		-	AAC configuration request
+ *	@inode: inode of device
+ *	@file: file handle
+ *	@cmd: ioctl command code
+ *	@arg: argument
+ *
+ *	Handles a configuration ioctl. Currently this involves wrapping it
+ *	up and feeding it into the nasty windowsalike glue layer.
+ *
+ *	Bugs: Needs locking against parallel ioctls lower down
+ *	Bugs: Needs to handle hot plugging
+ */
+ 
+static int aac_cfg_ioctl(struct inode * inode,  struct file * file, unsigned int cmd, unsigned long arg )
+{
+	struct aac_dev *dev = aac_devices[MINOR(inode->i_rdev)];
+	return aac_do_ioctl(dev, cmd, (void *)arg);
+}
+
+/*
+ *	To use the low level SCSI driver support using the linux kernel loadable 
+ *	module interface we should initialize the global variable driver_interface  
+ *	(datatype Scsi_Host_Template) and then include the file scsi_module.c.
+ */
+ 
+static Scsi_Host_Template driver_template = {
+	module:			THIS_MODULE,
+	name:           	"AAC",
+	proc_info:      	aac_procinfo,
+	detect:         	aac_detect,
+	release:        	aac_release,
+	info:           	aac_driverinfo,
+	ioctl:          	aac_ioctl,
+	command:        	aac_command,
+	queuecommand:   	aac_queuecommand,
+	abort:          	aac_abortcommand,
+	reset:          	aac_resetcommand,
+	bios_param:     	aac_biosparm,	
+	can_queue:      	AAC_NUM_IO_FIB,	
+	this_id:        	16,
+	sg_tablesize:   	16,
+	max_sectors:    	128,
+	cmd_per_lun:    	1,
+	eh_abort_handler:       aac_abortcommand,
+	use_clustering:		ENABLE_CLUSTERING,
+};
+
+#include "scsi_module.c"
+
+/**
+ *	aac_procinfo	-	Implement /proc/scsi/<drivername>/<n>
+ *	@proc_buffer: memory buffer for I/O
+ *	@start_ptr: pointer to first valid data
+ *	@offset: offset into file
+ *	@bytes_available: space left
+ *	@host_no: scsi host ident
+ *	@write: direction of I/O
+ *
+ *	Used to export driver statistics and other infos to the world outside 
+ *	the kernel using the proc file system. Also provides an interface to
+ *	feed the driver with information.
+ *
+ *		For reads
+ *			- if offset > 0 return 0
+ *			- if offset == 0 write data to proc_buffer and set the start_ptr to
+ *			beginning of proc_buffer, return the number of characters written.
+ *		For writes
+ *			- writes currently not supported, return 0
+ *
+ *	Bugs:	Only offset zero is handled
+ */
+
+static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset,
+			int bytes_available, int host_no, int write)
+{
+	if(write || offset > 0)
+		return 0;
+	*start_ptr = proc_buffer;
+	return sprintf(proc_buffer, "%s  %d\n", "Raid Controller, scsi hba number", host_no);
+}
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/rx.c linux/drivers/scsi/aacraid/rx.c
--- linux-2.4.16/drivers/scsi/aacraid/rx.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/rx.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,413 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  rx.c
+ *
+ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blk.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+static void aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned long bellbits;
+	u8 intstat, mask;
+
+	intstat = rx_readb(dev, MUnit.OISR);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have 
+	 *	been enabled.
+	 */
+	mask = ~(rx_readb(dev, MUnit.OIMR));
+	/* Check to see if this is our interrupt.  If it isn't just return */
+	if (intstat & mask) 
+	{
+		bellbits = rx_readl(dev, OutboundDoorbellReg);
+		if (bellbits & DoorBellPrintfReady)
+		{
+			aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5])));
+			rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+			rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdReady)
+		{
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+		}
+		else if (bellbits & DoorBellAdapterNormRespReady) 
+		{
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdNotFull)
+		{
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+		}
+		else if (bellbits & DoorBellAdapterNormRespNotFull)
+		{
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+		}
+	}
+}
+
+/**
+ *	aac_rx_enable_interrupt	-	Enable event reporting
+ *	@dev: Adapter
+ *	@event: Event to enable
+ *
+ *	Enable event reporting from the i960 for a given event.
+ */
+ 
+static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_rx_disable_interrupt	-	Disable event reporting
+ *	@dev: Adapter
+ *	@event: Event to enable
+ *
+ *	Disable event reporting from the i960 for a given event.
+ */
+
+static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	rx_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int rx_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *status)
+{
+	unsigned long start;
+	int ok;
+	/*
+	 *	Write the command into Mailbox 0
+	 */
+	rx_writel(dev, InboundMailbox0, cpu_to_le32(command));
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	rx_writel(dev, InboundMailbox1, cpu_to_le32(p1));
+	rx_writel(dev, InboundMailbox2, 0);
+	rx_writel(dev, InboundMailbox3, 0);
+	rx_writel(dev, InboundMailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Disable doorbell interrupts
+	 */
+	rx_writeb(dev, MUnit.OIMR, rx_readb(dev, MUnit.OIMR) | 0x04);
+	/*
+	 *	Force the completion of the mask register write before issuing
+	 *	the interrupt.
+	 */
+	rx_readb (dev, MUnit.OIMR);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	/*
+	 *	Wait up to 30 seconds
+	 */
+	while (time_before(start+30*HZ, jiffies)) 
+	{
+		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
+		/*
+		 *	Mon960 will set doorbell0 bit when it has completed the command.
+		 */
+		if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+			/*
+			 *	Clear the doorbell.
+			 */
+			rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+			ok = 1;
+			break;
+		}
+		/*
+		 *	Yield the processor in case we are slow 
+		 */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (ok != 1) {
+		/*
+		 *	Restore interrupt mask even though we timed out
+		 */
+		rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
+		return -ETIMEDOUT;
+	}
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	*status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0]));
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Restore interrupt mask
+	 */
+	rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
+	return 0;
+
+}
+
+/**
+ *	aac_rx_interrupt_adapter	-	interrupt adapter
+ *	@dev: Adapter
+ *
+ *	Send an interrupt to the i960 and breakpoint it.
+ */
+
+static void aac_rx_interrupt_adapter(struct aac_dev *dev)
+{
+	unsigned long ret;
+	rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_rx_notify_adapter		-	send an event to the adapter
+ *	@dev: Adapter
+ *	@event: Event to send
+ *
+ *	Notify the i960 that something it probably cares about has
+ *	happened.
+ */
+
+static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+		break;
+	case HostShutdown:
+//		rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
+		break;
+	case FastIo:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+/**
+ *	aac_rx_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an i960 based AAC adapter
+ */
+
+static void aac_rx_start_adapter(struct aac_dev *dev)
+{
+	unsigned long status;
+	struct aac_init *init;
+
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
+	/*
+	 *	Tell the adapter we are back and up and running so it will scan
+	 *	its command queues and enable our interrupts
+	 */
+	dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that we
+	 *	can handle.
+	 */
+	rx_writeb(dev, MUnit.OIMR, 0xff);
+	rx_writel(dev, MUnit.ODR, 0xffffffff);
+//	rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
+	rx_writeb(dev, MUnit.OIMR, 0xfb);
+
+	rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &status);
+}
+
+/**
+ *	aac_rx_init	-	initialize an i960 based AAC card
+ *	@dev: device to configure
+ *	@devnum: adapter number
+ *
+ *	Allocate and set up resources for the i960 based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_rx_init(struct aac_dev *dev, unsigned long num)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char * name;
+
+	dev->devnum = num;
+
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	if((dev->regs.rx = (struct rx_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map i960.\n" );
+		return -1;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (rx_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
+		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+		return -1;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
+		printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
+		return -1;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 30 seconds.
+	 */
+	while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) 
+	{
+		if(time_after(jiffies, start+30*HZ))
+		{
+			status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16;
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status);
+			return -1;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
+	{
+		printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
+		return -1;
+	}
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+	dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
+	dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt;
+	dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
+	dev->a_ops.adapter_notify = aac_rx_notify_adapter;
+
+	if (aac_init_adapter(dev) == NULL)
+		return -1;
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	/*
+	 *	Tell the adapter that all is configured, and it can start
+	 *	accepting requests
+	 */
+	aac_rx_start_adapter(dev);
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/aacraid/sap1sup.c linux/drivers/scsi/aacraid/sap1sup.c
--- linux-2.4.16/drivers/scsi/aacraid/sap1sup.c	Thu Jan  1 00:00:00 1970
+++ linux/drivers/scsi/aacraid/sap1sup.c	Sun Dec  9 18:12:25 2001
@@ -0,0 +1,394 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  sap1sup.c
+ *
+ * Abstract: Drawbridge specific support functions
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blk.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned short intstat, mask;
+
+	intstat = sa_readw(dev, DoorbellReg_p);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have been enabled.
+	 */
+	mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
+
+	/* Check to see if this is our interrupt.  If it isn't just return */
+
+	if (intstat & mask) {
+		if (intstat & PrintfReady) {
+			aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5)));
+			sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
+			sa_writew(dev, DoorbellReg_s, PrintfDone);
+		} else if (intstat & DOORBELL_1) {	// dev -> Host Normal Command Ready
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
+		} else if (intstat & DOORBELL_2) {	// dev -> Host Normal Response Ready
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
+		} else if (intstat & DOORBELL_3) {	// dev -> Host Normal Command Not Full
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
+		} else if (intstat & DOORBELL_4) {	// dev -> Host Normal Response Not Full
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
+		}
+	}
+}
+
+/**
+ *	aac_sa_enable_interrupt	-	enable an interrupt event
+ *	@dev: Which adapter to enable.
+ *	@event: Which adapter event.
+ *
+ *	This routine will enable the corresponding adapter event to cause an interrupt on 
+ * 	the host.
+ */
+ 
+void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_sa_disable_interrupt	-	disable an interrupt event
+ *	@dev: Which adapter to enable.
+ *	@event: Which adapter event.
+ *
+ *	This routine will enable the corresponding adapter event to cause an interrupt on 
+ * 	the host.
+ */
+
+void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_sa_notify_adapter		-	handle adapter notification
+ *	@dev:	Adapter that notification is for
+ *	@event:	Event to notidy
+ *
+ *	Notify the adapter of an event
+ */
+ 
+void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_3);
+		break;
+	case HostShutdown:
+		//sa_sync_cmd(dev, HOST_CRASHING, 0, &ret);
+		break;
+	case FastIo:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+
+/**
+ *	sa_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int sa_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *ret)
+{
+	unsigned long start;
+ 	int ok;
+	/*
+	 *	Write the Command into Mailbox 0
+	 */
+	sa_writel(dev, Mailbox0, cpu_to_le32(command));
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	sa_writel(dev, Mailbox1, cpu_to_le32(p1));
+	sa_writel(dev, Mailbox2, 0);
+	sa_writel(dev, Mailbox3, 0);
+	sa_writel(dev, Mailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	sa_writew(dev, DoorbellReg_s, DOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	while(time_before(jiffies, start+30*HZ))
+	{
+		/*
+		 *	Delay 5uS so that the monitor gets access
+		 */
+		udelay(5);
+		/*
+		 *	Mon110 will set doorbell0 bit when it has 
+		 *	completed the command.
+		 */
+		if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
+			ok = 1;
+			break;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if (ok != 1)
+		return -ETIMEDOUT;
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	*ret = le32_to_cpu(sa_readl(dev, Mailbox0));
+	return 0;
+}
+
+/**
+ *	aac_sa_interrupt_adapter	-	interrupt an adapter
+ *	@dev: Which adapter to enable.
+ *
+ *	Breakpoint an adapter.
+ */
+ 
+static void aac_sa_interrupt_adapter (struct aac_dev *dev)
+{
+	unsigned long ret;
+	sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_sa_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an ARM based AAC adapter
+ */
+
+static void aac_sa_start_adapter(struct aac_dev *dev)
+{
+	unsigned long ret;
+	struct aac_init *init;
+	/*
+	 * Fill in the remaining pieces of the init.
+	 */
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
+
+	dprintk(("INIT\n"));
+	/*
+	 * Tell the adapter we are back and up and running so it will scan its command
+	 * queues and enable our interrupts
+	 */
+	dev->irq_mask =	(PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that 
+	 *	we can handle.
+	 */
+	dprintk(("MASK\n"));
+	sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff));
+	sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
+	dprintk(("SYNCCMD\n"));
+	sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &ret);
+}
+
+/**
+ *	aac_sa_init	-	initialize an ARM based AAC card
+ *	@dev: device to configure
+ *	@devnum: adapter number
+ *
+ *	Allocate and set up resources for the ARM based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_sa_init(struct aac_dev *dev, unsigned long devnum)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char *name;
+
+	dev->devnum = devnum;
+
+	dprintk(("PREINST\n"));
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	dprintk(("PREMAP\n"));
+
+	if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map ARM.\n" );
+		return -1;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
+		printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
+		return -1;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
+		printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
+		return -1;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.
+	 */
+	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
+		if (time_after(start+180*HZ, jiffies)) {
+			status = sa_readl(dev, Mailbox7) >> 16;
+			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status));
+			return -1;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	dprintk(("ATIRQ\n"));
+	if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
+		printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
+		return -1;
+	}
+
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+
+	dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
+	dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
+	dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
+	dev->a_ops.adapter_notify = aac_sa_notify_adapter;
+
+	dprintk(("FUNCDONE\n"));
+
+	if(aac_init_adapter(dev) == NULL)
+		return -1;
+
+	dprintk(("NEWADAPTDONE\n"));
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	/*
+	 *	Tell the adapter that all is configure, and it can start 
+	 *	accepting requests
+	 */
+	dprintk(("STARTING\n"));
+	aac_sa_start_adapter(dev);
+	dprintk(("STARTED\n"));
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c
--- linux-2.4.16/drivers/scsi/dtc.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/dtc.c	Sun Dec  9 18:24:24 2001
@@ -1,13 +1,11 @@
-
 #define AUTOSENSE
 #define PSEUDO_DMA
 #define DONT_USE_INTR
-#define UNSAFE		/* Leave interrupts enabled during pseudo-dma I/O */
+#define UNSAFE			/* Leave interrupts enabled during pseudo-dma I/O */
 #define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\
 		 NDEBUG_SELECTION+NDEBUG_ARBITRATION)
 #define DMA_WORKS_RIGHT
 
-
 /*
  * DTC 3180/3280 driver, by
  *	Ray Van Tassle	rayvt@comm.mot.com
@@ -65,6 +63,7 @@
  6 = yellow
  7 = white
 */
+
 #if 0
 #define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
 #else
@@ -102,336 +101,318 @@
  */
 
 /*
- */ 
+ */
 /* Offset from DTC_5380_OFFSET */
 #define DTC_CONTROL_REG		0x100	/* rw */
 #define D_CR_ACCESS		0x80	/* ro set=can access 3280 registers */
 #define CSR_DIR_READ		0x40	/* rw direction, 1 = read 0 = write */
 
-#define CSR_RESET              0x80    /* wo  Resets 53c400 */
-#define CSR_5380_REG           0x80    /* ro  5380 registers can be accessed */
-#define CSR_TRANS_DIR          0x40    /* rw  Data transfer direction */
-#define CSR_SCSI_BUFF_INTR     0x20    /* rw  Enable int on transfer ready */
-#define CSR_5380_INTR          0x10    /* rw  Enable 5380 interrupts */
-#define CSR_SHARED_INTR        0x08    /* rw  Interrupt sharing */
-#define CSR_HOST_BUF_NOT_RDY   0x04    /* ro  Host buffer not ready */
-#define CSR_SCSI_BUF_RDY       0x02    /* ro  SCSI buffer ready */
-#define CSR_GATED_5380_IRQ     0x01    /* ro  Last block xferred */
+#define CSR_RESET              0x80	/* wo  Resets 53c400 */
+#define CSR_5380_REG           0x80	/* ro  5380 registers can be accessed */
+#define CSR_TRANS_DIR          0x40	/* rw  Data transfer direction */
+#define CSR_SCSI_BUFF_INTR     0x20	/* rw  Enable int on transfer ready */
+#define CSR_5380_INTR          0x10	/* rw  Enable 5380 interrupts */
+#define CSR_SHARED_INTR        0x08	/* rw  Interrupt sharing */
+#define CSR_HOST_BUF_NOT_RDY   0x04	/* ro  Host buffer not ready */
+#define CSR_SCSI_BUF_RDY       0x02	/* ro  SCSI buffer ready */
+#define CSR_GATED_5380_IRQ     0x01	/* ro  Last block xferred */
 #define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR)
 
 
-#define DTC_BLK_CNT		0x101   /* rw 
+#define DTC_BLK_CNT		0x101	/* rw 
 					 * # of 128-byte blocks to transfer */
 
 
-#define D_CR_ACCESS             0x80    /* ro set=can access 3280 registers */
+#define D_CR_ACCESS             0x80	/* ro set=can access 3280 registers */
 
 #define DTC_SWITCH_REG		0x3982	/* ro - DIP switches */
 #define DTC_RESUME_XFER		0x3982	/* wo - resume data xfer 
-					   * after disconnect/reconnect*/
+					   * after disconnect/reconnect */
 
 #define DTC_5380_OFFSET		0x3880	/* 8 registers here, see NCR5380.h */
 
 /*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */
-#define DTC_DATA_BUF		0x3900  /* rw 128 bytes long */
+#define DTC_DATA_BUF		0x3900	/* rw 128 bytes long */
 
 static struct override {
-   unsigned int address;
-   int irq;
+	unsigned int address;
+	int irq;
 } overrides
 #ifdef OVERRIDE
 [] __initdata = OVERRIDE;
 #else
-[4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}};
+[4] __initdata = { 
+	{0, IRQ_AUTO},
+	{0, IRQ_AUTO},
+	{0, IRQ_AUTO},
+	{0, IRQ_AUTO}
+};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
 static struct base {
-   unsigned long address;
-   int noauto;
-} bases[] __initdata = {{0xcc000, 0}, {0xc8000, 0}, {0xdc000, 0}, {0xd8000, 0}};
+	unsigned long address;
+	int noauto;
+} bases[] __initdata = {
+	{0xcc000, 0},
+	{0xc8000, 0},
+	{0xdc000, 0},
+	{0xd8000, 0}
+};
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
 static const struct signature {
-   const char *string;
-   int offset;
-} signatures[] = { {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, };
+	const char *string;
+	int offset;
+} signatures[] = { 
+	{"DATA TECHNOLOGY CORPORATION BIOS", 0x25},
+};
 
 #define NO_SIGNATURES (sizeof (signatures) /  sizeof (struct signature))
 
-/*
- * Function : dtc_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
+/**
+ *	dtc_setup	-	option setup for dtc3x80
  *
-*/
+ *	LILO command line initialization of the overrides array,
+ */
 
-void __init dtc_setup(char *str, int *ints){
-   static int commandline_current = 0;
-   int i;
-   if (ints[0] != 2)
-      printk("dtc_setup: usage dtc=address,irq\n");
-   else
-      if (commandline_current < NO_OVERRIDES) {
-      overrides[commandline_current].address = ints[1];
-      overrides[commandline_current].irq = ints[2];
-      for (i = 0; i < NO_BASES; ++i)
-	 if (bases[i].address == ints[1]) {
-	 bases[i].noauto = 1;
-	 break;
-      }
-      ++commandline_current;
-   }
+static int __init dtc_setup(char *str)
+{
+	static int commandline_current = 0;
+	int i;
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	
+	if (ints[0] != 2)
+		printk(KERN_ERR "dtc_setup: usage dtc=address,irq\n");
+	else if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].address = ints[1];
+		overrides[commandline_current].irq = ints[2];
+		for (i = 0; i < NO_BASES; ++i)
+			if (bases[i].address == ints[1]) {
+				bases[i].noauto = 1;
+				break;
+			}
+		++commandline_current;
+	}
+	return 1;
 }
 
-/* 
- * Function : int dtc_detect(Scsi_Host_Template * tpnt)
+__setup("dtc=", dtc_setup);
+
+/**
+ *	dtc_detect	-	detect DTC 3x80 controllers
+ *	@tpnt: controller template
  *
- * Purpose : detects and initializes DTC 3180/3280 controllers
+ *	Detects and initializes DTC 3180/3280 controllers
  *	that were autoprobed, overridden on the LILO command line, 
  *	or specified at compile time.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- * 
- * Returns : 1 if a host adapter was found, 0 if not.
- *
-*/
-
-int __init dtc_detect(Scsi_Host_Template * tpnt){
-   static int current_override = 0, current_base = 0;
-   struct Scsi_Host *instance;
-   unsigned int base;
-   int sig, count;
-
-   tpnt->proc_name = "dtc3x80";
-   tpnt->proc_info = &dtc_proc_info;
-
-   for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
-      base = 0;
-
-      if (overrides[current_override].address)
-	 base = overrides[current_override].address;
-      else
-	 for (; !base && (current_base < NO_BASES); ++current_base) {
-#if (DTCDEBUG & DTCDEBUG_INIT)
-	 printk("scsi-dtc : probing address %08x\n", bases[current_base].address);
-#endif
-	 for (sig = 0; sig < NO_SIGNATURES; ++sig)
-	    if (!bases[current_base].noauto && 
-		isa_check_signature(bases[current_base].address +
-				signatures[sig].offset,
-	      signatures[sig].string, strlen(signatures[sig].string))) {
-	    base = bases[current_base].address;
-#if (DTCDEBUG & DTCDEBUG_INIT)
-	    printk("scsi-dtc : detected board.\n");
-#endif
-	    break;
-	 }
-      }
-
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
-      printk("scsi-dtc : base = %08x\n", base);
-#endif
-
-      if (!base)
-	 break;
+ */
 
-      instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-      if(instance == NULL)
-      	break;
-      	
-      instance->base = base;
-
-      NCR5380_init(instance, 0);
-
-      NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */
-      if (overrides[current_override].irq != IRQ_AUTO)
-	 instance->irq = overrides[current_override].irq;
-      else
-	 instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
+int __init dtc_detect(Scsi_Host_Template * tpnt)
+{
+	static int current_override = 0, current_base = 0;
+	struct Scsi_Host *instance;
+	unsigned int base;
+	int sig, count;
+
+	tpnt->proc_name = "dtc3x80";
+	tpnt->proc_info = &dtc_proc_info;
+
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) 
+	{
+		base = 0;
+
+		if (overrides[current_override].address)
+			base = overrides[current_override].address;
+		else
+		{
+			for (; !base && (current_base < NO_BASES); ++current_base) {
+				for (sig = 0; sig < NO_SIGNATURES; ++sig)
+				{
+					if (!bases[current_base].noauto && isa_check_signature(bases[current_base].address + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
+						base = bases[current_base].address;
+						break;
+					}
+				}
+			}
+		}
+
+		if (!base)
+			break;
+
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL)
+			break;
+
+		instance->base = base;
+
+		NCR5380_init(instance, 0);
+
+		NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);	/* Enable int's */
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
 
 #ifndef DONT_USE_INTR
-/* With interrupts enabled, it will sometimes hang when doing heavy
- * reads. So better not enable them until I finger it out. */
-      if (instance->irq != IRQ_NONE)
-	 if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) {
-	 printk("scsi%d : IRQ%d not free, interrupts disabled\n",
-	      instance->host_no, instance->irq);
-	 instance->irq = IRQ_NONE;
-      }
-
-      if (instance->irq == IRQ_NONE) {
-	 printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
-	 printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
-      }
+		/* With interrupts enabled, it will sometimes hang when doing heavy
+		 * reads. So better not enable them until I figure it out. */
+		if (instance->irq != IRQ_NONE)
+			if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) 
+			{
+				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) {
+			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+		}
 #else
-      if (instance->irq != IRQ_NONE)
-	 printk("scsi%d : interrupts not used. Might as well not jumper it.\n",
-		instance->host_no);
-      instance->irq = IRQ_NONE;
+		if (instance->irq != IRQ_NONE)
+			printk(KERN_INFO "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
+		instance->irq = IRQ_NONE;
 #endif
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
-      printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
-
-      printk("scsi%d : at 0x%05X", instance->host_no, (int)instance->base);
-      if (instance->irq == IRQ_NONE)
-	 printk (" interrupts disabled");
-      else
-	 printk (" irq %d", instance->irq);
-      printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
-	   CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
-      NCR5380_print_options(instance);
-      printk("\n");
-
-      ++current_override;
-      ++count;
-   }
-   return count;
+		printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
+		if (instance->irq == IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
+
+		++current_override;
+		++count;
+	}
+	return count;
 }
 
-/*
- * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip)
+/**
+ *	dtc_biosparam		-	compute disk geometry
+ *	@disk: disk to generate for
+ *	@dev: major/minor of device
+ *	@ip: returned geometry
  *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ * 	Generates a BIOS / DOS compatible H-C-S mapping for 
  *	the specified device / size.
- * 
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- *	major / minor, ip[] = {heads, sectors, cylinders}  
- *
- * Returns : always 0 (success), initializes ip
- *	
-*/
-
-/* 
- * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
-*/
+ */
 
-int dtc_biosparam(Disk * disk, kdev_t dev, int * ip)
+int dtc_biosparam(Disk * disk, kdev_t dev, int *ip)
 {
-   int size = disk->capacity;
+	int size = disk->capacity;
 
-   ip[0] = 64;
-   ip[1] = 32;
-   ip[2] = size >> 11;
-   return 0;
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	return 0;
 }
 
 
-/****************************************************************
- * Function : int NCR5380_pread (struct Scsi_Host *instance, 
- *	unsigned char *dst, int len)
- *
- * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to 
- *	dst
- * 
- * Inputs : dst = destination, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog 
- * 	timeout.
-*/
-
 static int dtc_maxi = 0;
 static int dtc_wmaxi = 0;
 
-static inline int NCR5380_pread (struct Scsi_Host *instance,
-     unsigned char *dst, int len)
-     {
-   unsigned char *d = dst;
-   int i;	/* For counting time spent in the poll-loop */
-   NCR5380_local_declare();
-   NCR5380_setup(instance);
-
-   i = 0;
-   NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-   NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
-   if (instance->irq == IRQ_NONE)
-      NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
-   else
-      NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
-   NCR5380_write(DTC_BLK_CNT, len >> 7);        /* Block count */
-   rtrc(1);
-   while (len > 0) {
-      rtrc(2);
-      while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
-	 ++i;
-      rtrc(3);
-      isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128);
-      d += 128;
-      len -= 128;
-      rtrc(7);	/*** with int's on, it sometimes hangs after here.
+/**
+ *	NCR5380_pread 		-	fast pseudo DMA read
+ *	@instance: controller
+ *	@dst: destination buffer
+ *	@len: expected/max size
+ *
+ *	Fast 5380 pseudo-dma read function, reads len bytes from the controller
+ *	mmio area into dst.
+ */
+
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+	unsigned char *d = dst;
+	int i;			/* For counting time spent in the poll-loop */
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	i = 0;
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
+	if (instance->irq == IRQ_NONE)
+		NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
+	else
+		NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
+	NCR5380_write(DTC_BLK_CNT, len >> 7);	/* Block count */
+	rtrc(1);
+	while (len > 0) {
+		rtrc(2);
+		while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
+			++i;
+		rtrc(3);
+		isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128);
+		d += 128;
+		len -= 128;
+		rtrc(7);
+		/*** with int's on, it sometimes hangs after here.
 		 * Looks like something makes HBNR go away. */
-   }
-   rtrc(4);
-   while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
-      ++i;
-   NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
-   rtrc(0);
-   NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-   if (i > dtc_maxi)
-      dtc_maxi = i;
-   return(0);
+	}
+	rtrc(4);
+	while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
+		++i;
+	NCR5380_write(MODE_REG, 0);	/* Clear the operating mode */
+	rtrc(0);
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	if (i > dtc_maxi)
+		dtc_maxi = i;
+	return (0);
 }
 
-/****************************************************************
- * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
- *	unsigned char *src, int len)
+/**
+ *	NCR5380_pwrite 		-	fast pseudo DMA write
+ *	@instance: controller
+ *	@dst: destination buffer
+ *	@len: expected/max size
  *
- * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
- *	src
- * 
- * Inputs : src = source, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog 
- * 	timeout.
-*/
+ *	Fast 5380 pseudo-dma write function, writes len bytes to the
+ *	controller mmio area from src.
+ */
 
-static inline int NCR5380_pwrite (struct Scsi_Host *instance,
-     unsigned char *src, int len) {
-   int i;
-   NCR5380_local_declare();
-   NCR5380_setup(instance);
-
-   NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-   NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
-   /* set direction (write) */
-   if (instance->irq == IRQ_NONE)
-      NCR5380_write(DTC_CONTROL_REG, 0);
-   else
-      NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
-   NCR5380_write(DTC_BLK_CNT, len >> 7);        /* Block count */
-   for (i = 0; len > 0; ++i) {
-      rtrc(5);
-      /* Poll until the host buffer can accept data. */
-      while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
-	 ++i;
-      rtrc(3);
-      isa_memcpy_toio(base + DTC_DATA_BUF, src, 128);
-      src += 128;
-      len -= 128;
-   }
-   rtrc(4);
-   while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
-      ++i;
-   rtrc(6);
-   /* Wait until the last byte has been sent to the disk */
-   while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
-      ++i;
-   rtrc(7);
-   /* Check for parity error here. fixme. */
-   NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
-   rtrc(0);
-   if (i > dtc_wmaxi)
-      dtc_wmaxi = i;
-   return (0);
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+	int i;
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
+	/* set direction (write) */
+	if (instance->irq == IRQ_NONE)
+		NCR5380_write(DTC_CONTROL_REG, 0);
+	else
+		NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
+	NCR5380_write(DTC_BLK_CNT, len >> 7);	/* Block count */
+	for (i = 0; len > 0; ++i) {
+		rtrc(5);
+		/* Poll until the host buffer can accept data. */
+		while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
+			++i;
+		rtrc(3);
+		isa_memcpy_toio(base + DTC_DATA_BUF, src, 128);
+		src += 128;
+		len -= 128;
+	}
+	rtrc(4);
+	while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
+		++i;
+	rtrc(6);
+	/* Wait until the last byte has been sent to the disk */
+	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+		++i;
+	rtrc(7);
+	/* Check for parity error here. fixme. */
+	NCR5380_write(MODE_REG, 0);	/* Clear the operating mode */
+	rtrc(0);
+	if (i > dtc_wmaxi)
+		dtc_wmaxi = i;
+	return (0);
 }
 
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- linux-2.4.16/drivers/scsi/fdomain.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/fdomain.c	Sun Dec  9 18:13:45 2001
@@ -983,7 +983,7 @@
       /* Register the IRQ with the kernel */
 
       retcode = request_irq( interrupt_level,
-			     do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", NULL);
+			     do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt);
 
       if (retcode < 0) {
 	 if (retcode == -EINVAL) {
@@ -2033,6 +2033,15 @@
    }
    
    return 0;
+}
+
+int fdomain_16x0_release(struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq)
+		free_irq(shpnt->irq, shpnt);
+	if (shpnt->io_port && shpnt->n_io_port)
+		release_region(shpnt->io_port, shpnt->n_io_port);
+
 }
 
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/fdomain.h linux/drivers/scsi/fdomain.h
--- linux-2.4.16/drivers/scsi/fdomain.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/fdomain.h	Sun Dec  9 21:51:46 2001
@@ -34,6 +34,7 @@
 int        fdomain_16x0_biosparam( Disk *, kdev_t, int * );
 int        fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
 				   int length, int hostno, int inout );
+int        fdomain_16x0_release( struct Scsi_Host *shpnt );
 
 #define FDOMAIN_16X0 { proc_info:      fdomain_16x0_proc_info,           \
 		       detect:         fdomain_16x0_detect,              \
@@ -43,6 +44,7 @@
 		       abort:          fdomain_16x0_abort,               \
 		       reset:          fdomain_16x0_reset,               \
 		       bios_param:     fdomain_16x0_biosparam,           \
+		       release:        fdomain_16x0_release,		 \
 		       can_queue:      1, 				 \
 		       this_id:        6, 				 \
 		       sg_tablesize:   64, 				 \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- linux-2.4.16/drivers/scsi/g_NCR5380.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/g_NCR5380.c	Sun Dec  9 18:29:04 2001
@@ -77,7 +77,7 @@
  * 	IRQ line if overridden on the command line.
  *     
  */
- 
+
 /*
  * $Log: generic_NCR5380.c,v $
  */
@@ -124,787 +124,772 @@
 #include <linux/isapnp.h>
 
 #define NCR_NOT_SET 0
-static int ncr_irq=NCR_NOT_SET;
-static int ncr_dma=NCR_NOT_SET;
-static int ncr_addr=NCR_NOT_SET;
-static int ncr_5380=NCR_NOT_SET;
-static int ncr_53c400=NCR_NOT_SET;
-static int ncr_53c400a=NCR_NOT_SET;
-static int dtc_3181e=NCR_NOT_SET;
+static int ncr_irq = NCR_NOT_SET;
+static int ncr_dma = NCR_NOT_SET;
+static int ncr_addr = NCR_NOT_SET;
+static int ncr_5380 = NCR_NOT_SET;
+static int ncr_53c400 = NCR_NOT_SET;
+static int ncr_53c400a = NCR_NOT_SET;
+static int dtc_3181e = NCR_NOT_SET;
 
 static struct override {
 	NCR5380_implementation_fields;
-    int irq;
-    int dma;
-    int board;	/* Use NCR53c400, Ricoh, etc. extensions ? */
-} overrides 
-#ifdef GENERIC_NCR5380_OVERRIDE 
-    [] __initdata = GENERIC_NCR5380_OVERRIDE;
+	int irq;
+	int dma;
+	int board;		/* Use NCR53c400, Ricoh, etc. extensions ? */
+} overrides
+#ifdef GENERIC_NCR5380_OVERRIDE
+[] __initdata = GENERIC_NCR5380_OVERRIDE;
 #else
-    [1] __initdata = {{0,},};
+[1] __initdata = { { 0,},};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
-/*
- * Function : static internal_setup(int board, char *str, int *ints)
+/**
+ *	internal_setup		-	handle lilo command string override
+ *	@board:	BOARD_* identifier for the board
+ *	@str: unused
+ *	@ints: numeric parameters
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board, 
- * 	or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints - 
- *	array of integer parameters with ints[0] equal to the number of ints.
+ * 	Do LILO command line initialization of the overrides array. Display
+ *	errors when needed
  *
+ *	Locks: none
  */
 
-static void __init internal_setup(int board, char *str, int *ints){
-    static int commandline_current = 0;
-    switch (board) {
-    case BOARD_NCR5380:
-	if (ints[0] != 2 && ints[0] != 3) {
-	    printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
-	    return;
-	}
-	break;
-    case BOARD_NCR53C400:
-	if (ints[0] != 2) {
-	    printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
-	    return;
-	}
-	break;
-    case BOARD_NCR53C400A:
-	if (ints[0] != 2) {
-	    printk("generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
-	    return;
-	}
-	break;
-    case BOARD_DTC3181E:
-	if (ints[0] != 2) {
-	    printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
-	    return;
-	}
-	break;
-    }
-
-    if (commandline_current < NO_OVERRIDES) {
-	overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1];
-	overrides[commandline_current].irq = ints[2];
-	if (ints[0] == 3) 
-	    overrides[commandline_current].dma = ints[3];
-	else 
-	    overrides[commandline_current].dma = DMA_NONE;
-	overrides[commandline_current].board = board;
-	    ++commandline_current;
-    }
+static void __init internal_setup(int board, char *str, int *ints)
+{
+	static int commandline_current = 0;
+	switch (board) {
+	case BOARD_NCR5380:
+		if (ints[0] != 2 && ints[0] != 3) {
+			printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
+			return;
+		}
+		break;
+	case BOARD_NCR53C400:
+		if (ints[0] != 2) {
+			printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	case BOARD_NCR53C400A:
+		if (ints[0] != 2) {
+			printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	case BOARD_DTC3181E:
+		if (ints[0] != 2) {
+			printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	}
+
+	if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1];
+		overrides[commandline_current].irq = ints[2];
+		if (ints[0] == 3)
+			overrides[commandline_current].dma = ints[3];
+		else
+			overrides[commandline_current].dma = DMA_NONE;
+		overrides[commandline_current].board = board;
+		++commandline_current;
+	}
 }
 
-/*
- * Function : generic_NCR5380_setup (char *str, int *ints)
+/**
+ * 	do_NCR53C80_setup		-	set up entry point
+ *	@str: unused
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the ncr5380= command
+ *	line.
  */
 
-void __init generic_NCR5380_setup (char *str, int *ints){
-    internal_setup (BOARD_NCR5380, str, ints);
+static int __init do_NCR5380_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR5380, str, ints);
+	return 1;
 }
 
-/*
- * Function : generic_NCR53C400_setup (char *str, int *ints)
+/**
+ * 	do_NCR53C400_setup		-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the ncr53c400= command
+ *	line.
  */
 
-void __init generic_NCR53C400_setup (char *str, int *ints){
-    internal_setup (BOARD_NCR53C400, str, ints);
+static int __init do_NCR53C400_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR53C400, str, ints);
+	return 1;
 }
 
-/*
- * Function : generic_NCR53C400A_setup (char *str, int *ints)
+/**
+ * 	do_NCR53C400A_setup	-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the ncr53c400a= command
+ *	line.
  */
 
-void generic_NCR53C400A_setup (char *str, int *ints) {
-    internal_setup (BOARD_NCR53C400A, str, ints);
+static int __init do_NCR53C400A_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR53C400A, str, ints);
+	return 1;
 }
 
-/*
- * Function : generic_DTC3181E_setup (char *str, int *ints)
+/**
+ * 	do_DTC3181E_setup	-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the dtc3181e= command
+ *	line.
  */
 
-void generic_DTC3181E_setup (char *str, int *ints) {
-    internal_setup (BOARD_DTC3181E, str, ints);
+static int __init do_DTC3181E_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_DTC3181E, str, ints);
+	return 1;
 }
 
-/* 
- * Function : int generic_NCR5380_detect(Scsi_Host_Template * tpnt)
+/**
+ * 	generic_NCR5380_detect	-	look for NCR5380 controllers
+ *	@tpnt: the scsi template
  *
- * Purpose : initializes generic NCR5380 driver based on the 
- *	command line / compile time port and irq definitions.
+ *	Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E
+ *	and DTC436(ISAPnP) controllers. If overrides have been set we use
+ *	them.
  *
- * Inputs : tpnt - template for this SCSI adapter.
- * 
- * Returns : 1 if a host adapter was found, 0 if not.
+ *	The caller supplied NCR5380_init function is invoked from here, before
+ *	the interrupt line is taken.
  *
+ *	Locks: none
  */
 
-int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){
-    static int current_override = 0;
-    int count, i;
-    u_int *ports;
-    u_int ncr_53c400a_ports[] = {0x280, 0x290, 0x300, 0x310, 0x330,
-    		     		0x340, 0x348, 0x350, 0};
-    u_int dtc_3181e_ports[] = {0x220, 0x240, 0x280, 0x2a0, 0x2c0,
-    			     0x300, 0x320, 0x340, 0};
-    int flags = 0;
-    struct Scsi_Host *instance;
-
-    if (ncr_irq != NCR_NOT_SET)
-	overrides[0].irq=ncr_irq;
-    if (ncr_dma != NCR_NOT_SET)
-	overrides[0].dma=ncr_dma;
-    if (ncr_addr != NCR_NOT_SET)
-	overrides[0].NCR5380_map_name=(NCR5380_map_type)ncr_addr;
-    if (ncr_5380 != NCR_NOT_SET)
-	overrides[0].board=BOARD_NCR5380;
-    else if (ncr_53c400 != NCR_NOT_SET)
-	overrides[0].board=BOARD_NCR53C400;
-    else if (ncr_53c400a != NCR_NOT_SET)
-        overrides[0].board=BOARD_NCR53C400A;
-    else if (dtc_3181e != NCR_NOT_SET)
-        overrides[0].board=BOARD_DTC3181E;
-
-    if (!current_override && isapnp_present()) {
-	    struct pci_dev *dev = NULL;
-	    count = 0;
-	    while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), dev))) {
-		    if (count >= NO_OVERRIDES)
-			    break;
-		    if (!dev->active && dev->prepare(dev) < 0) {
-			    printk(KERN_ERR "dtc436e probe: prepare failed\n");
-			    continue;
-		    }
-		    if (!(dev->resource[0].flags & IORESOURCE_IO))
-			    continue;
-		    if (!dev->active && dev->activate(dev) < 0) {
-			    printk(KERN_ERR "dtc436e probe: activate failed\n");
-			    continue;
-		    }
-		    if (dev->irq_resource[0].flags & IORESOURCE_IRQ)
-			    overrides[count].irq=dev->irq_resource[0].start;
-		    else
-			    overrides[count].irq=IRQ_NONE;
-		    if (dev->dma_resource[0].flags & IORESOURCE_DMA)
-			    overrides[count].dma=dev->dma_resource[0].start;
-		    else
-			    overrides[count].dma=DMA_NONE;
-		    overrides[count].NCR5380_map_name=(NCR5380_map_type)dev->resource[0].start;
-		    overrides[count].board=BOARD_DTC3181E;
-		    count++;
-	    }
-    }
-
-    tpnt->proc_name = "g_NCR5380";
-
-    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
-	if (!(overrides[current_override].NCR5380_map_name))
-	    continue;
-
-	ports = 0;
-	switch (overrides[current_override].board) {
-	case BOARD_NCR5380:
-	    flags = FLAG_NO_PSEUDO_DMA;
-	    break;
-	case BOARD_NCR53C400:
-	    flags = FLAG_NCR53C400;
-	    break;
-	case BOARD_NCR53C400A:
-	    flags = FLAG_NO_PSEUDO_DMA;
-            ports = ncr_53c400a_ports;
-	    break;
-	case BOARD_DTC3181E:
-	    flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
-	    ports = dtc_3181e_ports;
-	    break;
+int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt)
+{
+	static int current_override = 0;
+	int count, i;
+	unsigned int *ports;
+	static unsigned int __initdata ncr_53c400a_ports[] = {
+		0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
+	};
+	static unsigned int __initdata dtc_3181e_ports[] = {
+		0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
+	};
+	int flags = 0;
+	struct Scsi_Host *instance;
+
+	if (ncr_irq != NCR_NOT_SET)
+		overrides[0].irq = ncr_irq;
+	if (ncr_dma != NCR_NOT_SET)
+		overrides[0].dma = ncr_dma;
+	if (ncr_addr != NCR_NOT_SET)
+		overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
+	if (ncr_5380 != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR5380;
+	else if (ncr_53c400 != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR53C400;
+	else if (ncr_53c400a != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR53C400A;
+	else if (dtc_3181e != NCR_NOT_SET)
+		overrides[0].board = BOARD_DTC3181E;
+
+	if (!current_override && isapnp_present()) {
+		struct pci_dev *dev = NULL;
+		count = 0;
+		while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) {
+			if (count >= NO_OVERRIDES)
+				break;
+			if (!dev->active && dev->prepare(dev) < 0) {
+				printk(KERN_ERR "dtc436e probe: prepare failed\n");
+				continue;
+			}
+			if (!(dev->resource[0].flags & IORESOURCE_IO))
+				continue;
+			if (!dev->active && dev->activate(dev) < 0) {
+				printk(KERN_ERR "dtc436e probe: activate failed\n");
+				continue;
+			}
+			if (dev->irq_resource[0].flags & IORESOURCE_IRQ)
+				overrides[count].irq = dev->irq_resource[0].start;
+			else
+				overrides[count].irq = IRQ_NONE;
+			if (dev->dma_resource[0].flags & IORESOURCE_DMA)
+				overrides[count].dma = dev->dma_resource[0].start;
+			else
+				overrides[count].dma = DMA_NONE;
+			overrides[count].NCR5380_map_name = (NCR5380_map_type) dev->resource[0].start;
+			overrides[count].board = BOARD_DTC3181E;
+			count++;
+		}
 	}
 
+	tpnt->proc_name = "g_NCR5380";
+
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+		if (!(overrides[current_override].NCR5380_map_name))
+			continue;
+
+		ports = 0;
+		switch (overrides[current_override].board) {
+		case BOARD_NCR5380:
+			flags = FLAG_NO_PSEUDO_DMA;
+			break;
+		case BOARD_NCR53C400:
+			flags = FLAG_NCR53C400;
+			break;
+		case BOARD_NCR53C400A:
+			flags = FLAG_NO_PSEUDO_DMA;
+			ports = ncr_53c400a_ports;
+			break;
+		case BOARD_DTC3181E:
+			flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
+			ports = dtc_3181e_ports;
+			break;
+		}
+
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	if (ports) {
-	    /* wakeup sequence for the NCR53C400A and DTC3181E*/
+		if (ports) {
+			/* wakeup sequence for the NCR53C400A and DTC3181E */
 
-	    /* Disable the adapter and look for a free io port */
-	    outb(0x59, 0x779);
-	    outb(0xb9, 0x379);
-	    outb(0xc5, 0x379);
-	    outb(0xae, 0x379);
-	    outb(0xa6, 0x379);
-	    outb(0x00, 0x379);
-
-	    if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
-	        for(i=0; ports[i]; i++) {
-	            if (overrides[current_override].NCR5380_map_name == ports[i])
-	                break;
-	        }
-	    else
-	        for(i=0; ports[i]; i++) {
-	            if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff))
-	                break;
-		}
-	    if (ports[i]) {
-	        outb(0x59, 0x779);
-	        outb(0xb9, 0x379);
-	        outb(0xc5, 0x379);
-	        outb(0xae, 0x379);
-	        outb(0xa6, 0x379);
-	        outb(0x80 | i, 0x379);          /* set io port to be used */
-        	outb(0xc0, ports[i] + 9);
-	        if (inb(ports[i] + 9) != 0x80)
-	            continue;
-	        else
-	            overrides[current_override].NCR5380_map_name=ports[i];
-	    } else
-	        continue;
-	}
+			/* Disable the adapter and look for a free io port */
+			outb(0x59, 0x779);
+			outb(0xb9, 0x379);
+			outb(0xc5, 0x379);
+			outb(0xae, 0x379);
+			outb(0xa6, 0x379);
+			outb(0x00, 0x379);
+
+			if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
+				for (i = 0; ports[i]; i++) {
+					if (overrides[current_override].NCR5380_map_name == ports[i])
+						break;
+			} else
+				for (i = 0; ports[i]; i++) {
+					if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff))
+						break;
+				}
+			if (ports[i]) {
+				outb(0x59, 0x779);
+				outb(0xb9, 0x379);
+				outb(0xc5, 0x379);
+				outb(0xae, 0x379);
+				outb(0xa6, 0x379);
+				outb(0x80 | i, 0x379);	/* set io port to be used */
+				outb(0xc0, ports[i] + 9);
+				if (inb(ports[i] + 9) != 0x80)
+					continue;
+				else
+					overrides[current_override].NCR5380_map_name = ports[i];
+			} else
+				continue;
+		}
 
-	request_region(overrides[current_override].NCR5380_map_name,
-					NCR5380_region_size, "ncr5380");
+		request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380");
 #else
-	if(check_mem_region(overrides[current_override].NCR5380_map_name,
-		NCR5380_region_size))
-		continue;
-	request_mem_region(overrides[current_override].NCR5380_map_name,
-					NCR5380_region_size, "ncr5380");
+		if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size))
+			continue;
+		request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380");
 #endif
-	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	if(instance == NULL)
-	{
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL) {
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-		release_region(overrides[current_override].NCR5380_map_name,
-	                                        NCR5380_region_size);
+			release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size);
 #else
-		release_mem_region(overrides[current_override].NCR5380_map_name,
-	                                  	NCR5380_region_size);
+			release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size);
 #endif
-		continue;
-	}
-	
-	instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
-
-	NCR5380_init(instance, flags);
-
-	if (overrides[current_override].irq != IRQ_AUTO)
-	    instance->irq = overrides[current_override].irq;
-	else 
-	    instance->irq = NCR5380_probe_irq(instance, 0xffff);
-
-	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
-		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
-		    instance->host_no, instance->irq);
-		instance->irq = IRQ_NONE;
-	    } 
+			continue;
+		}
 
-	if (instance->irq == IRQ_NONE) {
-	    printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
-	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
-	}
+		instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
 
-	printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name);
-	if (instance->irq == IRQ_NONE)
-	    printk (" interrupts disabled");
-	else 
-	    printk (" irq %d", instance->irq);
-	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
-	    CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
-	NCR5380_print_options(instance);
-	printk("\n");
+		NCR5380_init(instance, flags);
 
-	++current_override;
-	++count;
-    }
-    return count;
-}
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, 0xffff);
+
+		if (instance->irq != IRQ_NONE)
+			if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
+				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) {
+			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+		}
 
-const char * generic_NCR5380_info (struct Scsi_Host* host) {
-    static const char string[]="Generic NCR5380/53C400 Driver";
-    return string;
+		printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name);
+		if (instance->irq == IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
+
+		++current_override;
+		++count;
+	}
+	return count;
+}
+
+/**
+ *	generic_NCR5380_info	-	reporting string
+ *	@host: NCR5380 to report on
+ *
+ *	Report driver information for the NCR5380
+ */
+ 	
+const char *generic_NCR5380_info(struct Scsi_Host *host)
+{
+	static const char string[] = "Generic NCR5380/53C400 Driver";
+	return string;
 }
 
-int generic_NCR5380_release_resources(struct Scsi_Host * instance)
+/**
+ *	generic_NCR5380_release_resources	-	free resources
+ *	@instance: host adapter to clean up 
+ *
+ *	Free the generic interface resources from this adapter.
+ *
+ *	Locks: none
+ */
+ 
+int generic_NCR5380_release_resources(struct Scsi_Host *instance)
 {
-    NCR5380_local_declare();
-
-    NCR5380_setup(instance);
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
 
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-    release_region(instance->NCR5380_instance_name, NCR5380_region_size);
+	release_region(instance->NCR5380_instance_name, NCR5380_region_size);
 #else
-    release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
-#endif    
+	release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
+#endif
 
-    if (instance->irq != IRQ_NONE)
-	free_irq(instance->irq, NULL);
+	if (instance->irq != IRQ_NONE)
+		free_irq(instance->irq, NULL);
 
 	return 0;
 }
 
 #ifdef BIOSPARAM
-/*
- * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
+/**
+ *	generic_NCR5380_biosparam
+ *	@disk: disk to compute geometry for
+ *	@dev: device identifier for this disk
+ *	@ip: sizes to fill in
  *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
- *	the specified device / size.
+ *	Generates a BIOS / DOS compatible H-C-S mapping for the specified 
+ *	device / size.
  * 
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- *	major / minor, ip[] = {heads, sectors, cylinders}  
+ * 	XXX Most SCSI boards use this mapping, I could be incorrect.  Someone
+ *	using hard disks on a trantor should verify that this mapping
+ *	corresponds to that used by the BIOS / ASPI driver by running the linux
+ *	fdisk program and matching the H_C_S coordinates to what DOS uses.
  *
- * Returns : always 0 (success), initializes ip
- *	
- */
-
-/* 
- * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
+ *	Locks: none
  */
 
 int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
 {
-  int size = disk->capacity;
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  return 0;
+	int size = disk->capacity;
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	return 0;
 }
 #endif
 
 #if NCR53C400_PSEUDO_DMA
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,    int len)
-{
-    int blocks = len / 128;
-    int start = 0;
-    int bl;
-#ifdef CONFIG_SCSI_G_NCR5380_PORT
-    int i;
-#endif 
-
-    NCR5380_local_declare();
-
-    NCR5380_setup(instance);
-
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len);
-#endif
-
-    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
-    NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
-    while (1) {
-    
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: %d blocks left\n", blocks);
-#endif
-
-	if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	    if (blocks)
-		printk("53C400r: blocks still == %d\n", blocks);
-	    else
-		printk("53C400r: Exiting loop\n");
-#endif
-	    break;
-	}
 
-#if 1
-	if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
-	    printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
-	    return -1;
-	}
-#endif
-
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: Waiting for buffer, bl=%d\n", bl);
-#endif
-
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: Transferring 128 bytes\n");
-#endif
+/**
+ *	NCR5380_pread		-	pseudo DMA read
+ *	@instance: adapter to read from
+ *	@dst: buffer to read into
+ *	@len: buffer length
+ *
+ *	Perform a psuedo DMA mode read from an NCR53C400 or equivalent
+ *	controller
+ */
+ 
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+	int blocks = len / 128;
+	int start = 0;
+	int bl;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
+	NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+	while (1) {
+		if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+			break;
+		}
+		if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+			printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+			return -1;
+		}
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
 
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
+		{
+			int i;
+			for (i = 0; i < 128; i++)
+				dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
-#endif
-	start+=128;
-	blocks--;
-    }
-
-    if (blocks) {
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: EXTRA: Waiting for buffer\n");
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128);
 #endif
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
+		start += 128;
+		blocks--;
+	}
+
+	if (blocks) {
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+		{
+			// FIXME - no timeout
+		}
 
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: Transferring EXTRA 128 bytes\n");
-#endif
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
+		{
+			int i;	
+			for (i = 0; i < 128; i++)
+				dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
-#endif
-	start+=128;
-	blocks--;
-    }
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    else
-	printk("53C400r: No EXTRA required\n");
-#endif
-
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    printk("53C400r: Final values: blocks=%d   start=%d\n", blocks, start);
-#endif
-
-    if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
-	printk("53C400r: no 53C80 gated irq after transfer");
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    else
-	printk("53C400r: Got 53C80 interrupt and tried to clear it\n");
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128);
 #endif
+		start += 128;
+		blocks--;
+	}
 
-/* DON'T DO THIS - THEY NEVER ARRIVE!
-    printk("53C400r: Waiting for 53C80 registers\n");
-    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
-	;
-*/
+	if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+		printk("53C400r: no 53C80 gated irq after transfer");
 
-    if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
-	printk("53C400r: no end dma signal\n");
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    else
-	printk("53C400r: end dma as expected\n");
+#if 0
+	/*
+	 *	DON'T DO THIS - THEY NEVER ARRIVE!
+	 */
+	printk("53C400r: Waiting for 53C80 registers\n");
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+		;
 #endif
-
-    NCR5380_write(MODE_REG, MR_BASE);
-    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-    return 0;
-}
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
+		printk(KERN_ERR "53C400r: no end dma signal\n");
 		
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,    int len)
-{
-    int blocks = len / 128;
-    int start = 0;
-    int i;
-    int bl;
-    NCR5380_local_declare();
-
-    NCR5380_setup(instance);
-
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len);
-#endif
-
-    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
-    NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
-    while (1) {
-	if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
-	    printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
-	    return -1;
-	}
-
-	if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	    if (blocks)
-		printk("53C400w: exiting loop, blocks still == %d\n", blocks);
-	    else
-		printk("53C400w: exiting loop\n");
-#endif
-	    break;
-	}
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	return 0;
+}
 
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: %d blocks left\n", blocks);
+/**
+ *	NCR5380_write		-	pseudo DMA write
+ *	@instance: adapter to read from
+ *	@dst: buffer to read into
+ *	@len: buffer length
+ *
+ *	Perform a psuedo DMA mode read from an NCR53C400 or equivalent
+ *	controller
+ */
 
-	printk("53C400w: waiting for buffer, bl=%d\n", bl);
-#endif
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+	int blocks = len / 128;
+	int start = 0;
+	int bl;
+	int i;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
+	NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+	while (1) {
+		if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+			printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+			return -1;
+		}
 
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: transferring 128 bytes\n");
-#endif
+		if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+			break;
+		}
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+			; // FIXME - timeout
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
+		{
+			for (i = 0; i < 128; i++)
+				NCR5380_write(C400_HOST_BUFFER, src[start + i]);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128);
 #endif
-	start+=128;
-	blocks--;
-    }
-    if (blocks) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: EXTRA waiting for buffer\n");
-#endif
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
+		start += 128;
+		blocks--;
+	}
+	if (blocks) {
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+			; // FIXME - no timeout
 
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: transferring EXTRA 128 bytes\n");
-#endif
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
+		{
+			for (i = 0; i < 128; i++)
+				NCR5380_write(C400_HOST_BUFFER, src[start + i]);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
-#endif
-	start+=128;
-	blocks--;
-    }
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    else
-	printk("53C400w: No EXTRA required\n");
-#endif
-    
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w: Final values: blocks=%d   start=%d\n", blocks, start);
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128);
 #endif
+		start += 128;
+		blocks--;
+	}
 
 #if 0
-    printk("53C400w: waiting for registers to be available\n");
-    THEY NEVER DO!
-    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
-	;
-    printk("53C400w: Got em\n");
-#endif
-
-    /* Let's wait for this instead - could be ugly */
-    /* All documentation says to check for this. Maybe my hardware is too
-     * fast. Waiting for it seems to work fine! KLL
-     */
-    while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
-	;
-
-    /*
-     * I know. i is certainly != 0 here but the loop is new. See previous
-     * comment.
-     */
-    if (i) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: got 53C80 gated irq (last block)\n");
-#endif
-	if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
-	    printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i);
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	else
-	    printk("53C400w: Got END OF DMA\n");
-#endif
-    }
-    else
-	printk("53C400w: no 53C80 gated irq after transfer (last block)\n");
+	printk("53C400w: waiting for registers to be available\n");
+	THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG);
+	printk("53C400w: Got em\n");
+#endif
+
+	/* Let's wait for this instead - could be ugly */
+	/* All documentation says to check for this. Maybe my hardware is too
+	 * fast. Waiting for it seems to work fine! KLL
+	 */
+	while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+		;	// FIXME - no timeout
+
+	/*
+	 * I know. i is certainly != 0 here but the loop is new. See previous
+	 * comment.
+	 */
+	if (i) {
+		if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
+			printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i);
+	} else
+		printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n");
 
 #if 0
-    if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
-	printk("53C400w: no end dma signal\n");
-    }
-#endif
-
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w: waiting for last byte...\n");
-#endif
-    while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
-    	;
-
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w:     got last byte.\n");
-    printk("53C400w: pwrite exiting with status 0, whoopee!\n");
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
+		printk(KERN_ERR "53C400w: no end dma signal\n");
+	}
 #endif
-    return 0;
+	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+		; 	// TIMEOUT
+	return 0;
 }
-#endif /* PSEUDO_DMA */
+#endif				/* PSEUDO_DMA */
 
+/*
+ *	Include the NCR5380 core code that we build our driver around	
+ */
+ 
 #include "NCR5380.c"
 
 #define PRINTP(x) len += sprintf(buffer+len, x)
 #define ANDP ,
 
-static int sprint_opcode(char* buffer, int len, int opcode) {
-    int start = len;
-    PRINTP("0x%02x " ANDP opcode);
-    return len-start;
-}
-
-static int sprint_command (char* buffer, int len, unsigned char *command) {
-    int i,s,start=len;
-    len += sprint_opcode(buffer, len, command[0]);
-    for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
-	PRINTP("%02x " ANDP command[i]);
-    PRINTP("\n");
-    return len-start;
-}
-
-static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) {
-    int start = len;
-    PRINTP("host number %d destination target %d, lun %d\n" ANDP
-       cmd->host->host_no ANDP
-       cmd->target ANDP
-       cmd->lun);
-    PRINTP("        command = ");
-    len += sprint_command (buffer, len, cmd->cmnd);
-    return len-start;
-}
-
-int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
-{
-    int len = 0;
-    NCR5380_local_declare();
-    unsigned long flags;
-    unsigned char status;
-    int i;
-    struct Scsi_Host *scsi_ptr;
-    Scsi_Cmnd *ptr;
-    struct NCR5380_hostdata *hostdata;
+static int sprint_opcode(char *buffer, int len, int opcode)
+{
+	int start = len;
+	PRINTP("0x%02x " ANDP opcode);
+	return len - start;
+}
+
+static int sprint_command(char *buffer, int len, unsigned char *command)
+{
+	int i, s, start = len;
+	len += sprint_opcode(buffer, len, command[0]);
+	for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+		PRINTP("%02x " ANDP command[i]);
+	PRINTP("\n");
+	return len - start;
+}
+
+/**
+ *	sprintf_Scsi_Cmnd	-	print a scsi command
+ *	@buffer: buffr to print into
+ *	@len: buffer length
+ *	@cmd: SCSI command block
+ *	
+ *	Print out the target and command data in hex
+ */
+
+static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd)
+{
+	int start = len;
+	PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->host->host_no ANDP cmd->target ANDP cmd->lun);
+	PRINTP("        command = ");
+	len += sprint_command(buffer, len, cmd->cmnd);
+	return len - start;
+}
+
+/**
+ *	generic_NCR5380_proc_info	-	/proc for NCR5380 driver
+ *	@buffer: buffer to print into
+ *	@start: start position
+ *	@offset: offset into buffer
+ *	@len: length
+ *	@hostno: instance to affect
+ *	@inout: read/write
+ *
+ *	Provide the procfs information for the 5380 controller. We fill
+ *	this with useful debugging information including the commands
+ *	being executed, disconnected command queue and the statistical
+ *	data
+ *
+ *	Locks: global cli/lock for queue walk
+ */
+ 
+int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+	int len = 0;
+	NCR5380_local_declare();
+	unsigned long flags;
+	unsigned char status;
+	int i;
+	struct Scsi_Host *scsi_ptr;
+	Scsi_Cmnd *ptr;
+	struct NCR5380_hostdata *hostdata;
 #ifdef NCR5380_STATS
-    Scsi_Device *dev;
-    extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+	Scsi_Device *dev;
+	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #endif
-    save_flags(flags);
-    cli();
+	save_flags(flags);
+	cli();
 
-    for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
-	if (scsi_ptr->host_no == hostno)
-	    break;
-    NCR5380_setup(scsi_ptr);
-    hostdata = (struct NCR5380_hostdata *)scsi_ptr->hostdata;
-
-    PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
-    PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
-    PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
+	for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr = scsi_ptr->next)
+		if (scsi_ptr->host_no == hostno)
+			break;
+	NCR5380_setup(scsi_ptr);
+	hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata;
+
+	PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
+	PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
+	PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
 #ifdef NCR53C400
-    PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
-    PRINTP("NCR53C400 card%s detected\n" ANDP  (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not");
+	PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
+	PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not");
 # if NCR53C400_PSEUDO_DMA
-    PRINTP("NCR53C400 pseudo DMA used\n");
+	PRINTP("NCR53C400 pseudo DMA used\n");
 # endif
 #else
-    PRINTP("NO NCR53C400 driver extensions\n");
+	PRINTP("NO NCR53C400 driver extensions\n");
 #endif
-    PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
-    if (scsi_ptr->irq == IRQ_NONE)
-	PRINTP("no interrupt\n");
-    else
-	PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
+	PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
+	if (scsi_ptr->irq == IRQ_NONE)
+		PRINTP("no interrupt\n");
+	else
+		PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
 
 #ifdef NCR5380_STATS
-    if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
-	PRINTP("There are commands pending, transfer rates may be crud\n");
-    if (hostdata->pendingr)
-	PRINTP("  %d pending reads" ANDP hostdata->pendingr);
-    if (hostdata->pendingw)
-	PRINTP("  %d pending writes" ANDP hostdata->pendingw);
-    if (hostdata->pendingr || hostdata->pendingw)
-	PRINTP("\n");
-    for (dev = scsi_ptr->host_queue; dev; dev=dev->next) {
-	    unsigned long br = hostdata->bytes_read[dev->id];
-	    unsigned long bw = hostdata->bytes_write[dev->id];
-	    long tr = hostdata->time_read[dev->id] / HZ;
-	    long tw = hostdata->time_write[dev->id] / HZ;
-
-	    PRINTP("  T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown");
-	    for (i=0; i<8; i++)
-		if (dev->vendor[i] >= 0x20)
-		    *(buffer+(len++)) = dev->vendor[i];
-	    *(buffer+(len++)) = ' ';
-	    for (i=0; i<16; i++)
-		if (dev->model[i] >= 0x20)
-		    *(buffer+(len++)) = dev->model[i];
-	    *(buffer+(len++)) = ' ';
-	    for (i=0; i<4; i++)
-		if (dev->rev[i] >= 0x20)
-		    *(buffer+(len++)) = dev->rev[i];
-	    *(buffer+(len++)) = ' ';
-				    
-	    PRINTP("\n%10ld kb read    in %5ld secs" ANDP br/1024 ANDP tr);
-	    if (tr)
-		PRINTP(" @ %5ld bps" ANDP br / tr); 
-
-	    PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw);
-	    if (tw)
-		PRINTP(" @ %5ld bps" ANDP bw / tw); 
-	    PRINTP("\n");
-    }
-#endif
-	
-    status = NCR5380_read(STATUS_REG);
-    if (!(status & SR_REQ))
-	PRINTP("REQ not asserted, phase unknown.\n");
-    else {
-	for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
-		    (phases[i].value != (status & PHASE_MASK)); ++i)
-	    ;
-	PRINTP("Phase %s\n" ANDP phases[i].name);
-    }
-
-    if (!hostdata->connected) {
-	PRINTP("No currently connected command\n");
-    } else {
-	len += sprint_Scsi_Cmnd (buffer, len, (Scsi_Cmnd *) hostdata->connected);
-    }
-
-    PRINTP("issue_queue\n");
-
-    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr;
-		ptr = (Scsi_Cmnd *) ptr->host_scribble)
-	len += sprint_Scsi_Cmnd (buffer, len, ptr);
-
-    PRINTP("disconnected_queue\n");
-
-    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
-		ptr = (Scsi_Cmnd *) ptr->host_scribble)
-	len += sprint_Scsi_Cmnd (buffer, len, ptr);
-	
-    *start = buffer + offset;
-    len -= offset;
-    if (len > length)
-	    len = length;
-    restore_flags(flags);
-    return len;
+	if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
+		PRINTP("There are commands pending, transfer rates may be crud\n");
+	if (hostdata->pendingr)
+		PRINTP("  %d pending reads" ANDP hostdata->pendingr);
+	if (hostdata->pendingw)
+		PRINTP("  %d pending writes" ANDP hostdata->pendingw);
+	if (hostdata->pendingr || hostdata->pendingw)
+		PRINTP("\n");
+	for (dev = scsi_ptr->host_queue; dev; dev = dev->next) {
+		unsigned long br = hostdata->bytes_read[dev->id];
+		unsigned long bw = hostdata->bytes_write[dev->id];
+		long tr = hostdata->time_read[dev->id] / HZ;
+		long tw = hostdata->time_write[dev->id] / HZ;
+
+		PRINTP("  T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
+		for (i = 0; i < 8; i++)
+			if (dev->vendor[i] >= 0x20)
+				*(buffer + (len++)) = dev->vendor[i];
+		*(buffer + (len++)) = ' ';
+		for (i = 0; i < 16; i++)
+			if (dev->model[i] >= 0x20)
+				*(buffer + (len++)) = dev->model[i];
+		*(buffer + (len++)) = ' ';
+		for (i = 0; i < 4; i++)
+			if (dev->rev[i] >= 0x20)
+				*(buffer + (len++)) = dev->rev[i];
+		*(buffer + (len++)) = ' ';
+
+		PRINTP("\n%10ld kb read    in %5ld secs" ANDP br / 1024 ANDP tr);
+		if (tr)
+			PRINTP(" @ %5ld bps" ANDP br / tr);
+
+		PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw);
+		if (tw)
+			PRINTP(" @ %5ld bps" ANDP bw / tw);
+		PRINTP("\n");
+	}
+#endif
+
+	status = NCR5380_read(STATUS_REG);
+	if (!(status & SR_REQ))
+		PRINTP("REQ not asserted, phase unknown.\n");
+	else {
+		for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
+		PRINTP("Phase %s\n" ANDP phases[i].name);
+	}
+
+	if (!hostdata->connected) {
+		PRINTP("No currently connected command\n");
+	} else {
+		len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected);
+	}
+
+	PRINTP("issue_queue\n");
+
+	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		len += sprint_Scsi_Cmnd(buffer, len, ptr);
+
+	PRINTP("disconnected_queue\n");
+
+	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		len += sprint_Scsi_Cmnd(buffer, len, ptr);
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	restore_flags(flags);
+	return len;
 }
 
 #undef PRINTP
 #undef ANDP
 
-/* Eventually this will go into an include file, but this will be later */
+/*
+ *	Eventually this will go into an include file, but this will be later 
+ */
 static Scsi_Host_Template driver_template = GENERIC_NCR5380;
 
 #include <linux/module.h>
 #include "scsi_module.c"
 
-#ifdef MODULE 
-
 MODULE_PARM(ncr_irq, "i");
 MODULE_PARM(ncr_dma, "i");
 MODULE_PARM(ncr_addr, "i");
@@ -913,46 +898,49 @@
 MODULE_PARM(ncr_53c400a, "i");
 MODULE_PARM(dtc_3181e, "i");
 MODULE_LICENSE("GPL");
-#else
 
-static int __init do_NCR5380_setup(char *str)
-{
-        int ints[10];
 
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_NCR5380_setup(str,ints);
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{
+	 ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+	 ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e),
+	 0},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
 
-        return 1;
-}
+
+#ifndef MODULE
 
 static int __init do_NCR53C400_setup(char *str)
 {
-        int ints[10];
+	int ints[10];
 
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_NCR53C400_setup(str,ints);
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	generic_NCR53C400_setup(str, ints);
 
-        return 1;
+	return 1;
 }
 
 static int __init do_NCR53C400A_setup(char *str)
 {
-        int ints[10];
+	int ints[10];
 
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_NCR53C400A_setup(str,ints);
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	generic_NCR53C400A_setup(str, ints);
 
-        return 1;
+	return 1;
 }
 
 static int __init do_DTC3181E_setup(char *str)
 {
-        int ints[10];
+	int ints[10];
 
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_DTC3181E_setup(str,ints);
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	generic_DTC3181E_setup(str, ints);
 
-        return 1;
+	return 1;
 }
 
 __setup("ncr5380=", do_NCR5380_setup);
@@ -960,18 +948,4 @@
 __setup("ncr53c400a=", do_NCR53C400A_setup);
 __setup("dtc3181e=", do_DTC3181E_setup);
 
-static struct isapnp_device_id id_table[] __devinitdata = {
-	{
-		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), 
-		0
-	},
-	{0}
-};
-
-MODULE_DEVICE_TABLE(isapnp, id_table);
-MODULE_LICENSE("GPL");
-
-
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h
--- linux-2.4.16/drivers/scsi/g_NCR5380.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/g_NCR5380.h	Sun Dec  9 18:29:04 2001
@@ -43,24 +43,18 @@
 #define NCR5380_BIOSPARAM NULL
 #endif
 
-#ifndef ASM
 int generic_NCR5380_abort(Scsi_Cmnd *);
 int generic_NCR5380_detect(Scsi_Host_Template *);
 int generic_NCR5380_release_resources(struct Scsi_Host *);
-int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int generic_NCR5380_reset(Scsi_Cmnd *, unsigned int);
-int notyet_generic_proc_info (char *buffer ,char **start, off_t offset,
-                     int length, int hostno, int inout);
-const char* generic_NCR5380_info(struct Scsi_Host *);
+int notyet_generic_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+const char *generic_NCR5380_info(struct Scsi_Host *);
 #ifdef BIOSPARAM
 int generic_NCR5380_biosparam(Disk *, kdev_t, int *);
 #endif
 
-int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout);
-
-#ifndef NULL
-#define NULL 0
-#endif
+int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
 #ifndef CMD_PER_LUN
 #define CMD_PER_LUN 2
@@ -92,19 +86,15 @@
 #define STRVAL(x) __STRVAL(x)
 
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-
 #define NCR5380_map_config port
-
 #define NCR5380_map_type int
-
 #define NCR5380_map_name port
-
 #define NCR5380_instance_name io_port
-
 #define NCR53C400_register_offset 0
-
 #define NCR53C400_address_adjust 8
-
+/*
+ *	FIXME: size should be runtime decided
+ */
 #ifdef NCR53C400
 #define NCR5380_region_size 16
 #else
@@ -114,28 +104,19 @@
 #define NCR5380_read(reg) (inb(NCR5380_map_name + (reg)))
 #define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg))))
 
-#else 
+#else
 /* therefore CONFIG_SCSI_G_NCR5380_MEM */
 
 #define NCR5380_map_config memory
-
 #define NCR5380_map_type unsigned long
-
 #define NCR5380_map_name base
-
 #define NCR5380_instance_name base
-
 #define NCR53C400_register_offset 0x108
-
 #define NCR53C400_address_adjust 0
-
 #define NCR53C400_mem_base 0x3880
-
 #define NCR53C400_host_buffer 0x3900
-
 #define NCR5380_region_size 0x3a00
 
-
 #define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg))
 #define NCR5380_write(reg, value) isa_writeb(NCR5380_map_name + NCR53C400_mem_base + (reg), value)
 
@@ -164,7 +145,5 @@
 #define BOARD_NCR53C400A 2
 #define BOARD_DTC3181E	3
 
-#endif /* else def HOSTS_C */
-#endif /* ndef ASM */
-#endif /* GENERIC_NCR5380_H */
-
+#endif				/* else def HOSTS_C */
+#endif				/* GENERIC_NCR5380_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- linux-2.4.16/drivers/scsi/ide-scsi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/ide-scsi.c	Tue Dec  4 19:25:31 2001
@@ -785,7 +785,7 @@
 	rq->buffer = (char *) pc;
 	rq->bh = idescsi_dma_bh (drive, pc);
 	rq->cmd = IDESCSI_PC_RQ;
-	spin_unlock(&io_request_lock);
+	spin_unlock_irq(&io_request_lock);
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
 	spin_lock_irq(&io_request_lock);
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- linux-2.4.16/drivers/scsi/megaraid.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/megaraid.c	Tue Dec  4 19:25:31 2001
@@ -4296,15 +4296,7 @@
 	int heads, cyls, sectors;
 	int capacity = disk->capacity;
 
-	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)))
+	if(!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
 		return -1;
 
 	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- linux-2.4.16/drivers/scsi/ncr53c8xx.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/ncr53c8xx.c	Wed Dec  5 20:22:25 2001
@@ -22,7 +22,7 @@
 **  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
 **  and is currently maintained by
 **
-**          Gerard Roudier              <groudier@club-internet.fr>
+**          Gerard Roudier              <groudier@free.fr>
 **
 **  Being given that this driver originates from the FreeBSD version, and
 **  in order to keep synergy on both, any suggested enhancements and corrections
@@ -63,7 +63,7 @@
 **  August 18 1997 by Cort <cort@cs.nmt.edu>:
 **     Support for Power/PC (Big Endian).
 **
-**  June 20 1998 by Gerard Roudier <groudier@club-internet.fr>:
+**  June 20 1998 by Gerard Roudier
 **     Support for up to 64 tags per lun.
 **     O(1) everywhere (C and SCRIPTS) for normal cases.
 **     Low PCI traffic for command handling when on-chip RAM is present.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- linux-2.4.16/drivers/scsi/ncr53c8xx.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/ncr53c8xx.h	Wed Dec  5 20:22:25 2001
@@ -22,7 +22,7 @@
 **  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
 **  and is currently maintained by
 **
-**          Gerard Roudier              <groudier@club-internet.fr>
+**          Gerard Roudier              <groudier@free.fr>
 **
 **  Being given that this driver originates from the FreeBSD version, and
 **  in order to keep synergy on both, any suggested enhancements and corrections
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- linux-2.4.16/drivers/scsi/osst.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/osst.c	Tue Dec  4 19:25:31 2001
@@ -16,15 +16,15 @@
   Copyright 1992 - 2000 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $
+  $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $
 
   Microscopic alterations - Rik Ling, 2000/12/21
   Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
-static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $";
-const char * osst_version = "0.9.8";
+static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $";
+const char * osst_version = "0.9.10";
 
 /* The "failure to reconnect" firmware bug */
 #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
@@ -225,20 +225,20 @@
 		 SRpnt->sr_cmnd[0] != MODE_SENSE &&
 		 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
 		if (driver_byte(result) & DRIVER_SENSE) {
-			printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev);
-			print_req_sense("osst", SRpnt);
+			printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev);
+			print_req_sense("osst:", SRpnt);
 		}
 		else {
 			static	int	notyetprinted = 1;
 
 			printk(KERN_WARNING
-			     "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			     "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
 			     dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
 			     host_byte(result));
 			if (notyetprinted) {
 				notyetprinted = 0;
 				printk(KERN_INFO
-					"osst%d:I: This error may be caused by your scsi controller,\n", dev);
+					"osst%d:I: This warning may be caused by your scsi controller,\n", dev);
 				printk(KERN_INFO
 					"osst%d:I: it has been reported with some Buslogic cards.\n", dev);
 			}
@@ -270,11 +270,10 @@
 /* Wakeup from interrupt */
 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
 {
-	unsigned int dev;
+	unsigned int dev = TAPE_NR(SCpnt->request.rq_dev);
 	OS_Scsi_Tape * STp;
 
-	if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) {
-		STp = os_scsi_tapes[dev];
+	if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) {
 		if ((STp->buffer)->writing &&
 		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 		    (SCpnt->sense_buffer[2] & 0x40)) {
@@ -480,7 +479,8 @@
 			for (i=0; i < STp->buffer->sg_segs; i++)
 				memset(STp->buffer->sg[i].address, 0, STp->buffer->sg[i].length);
 			strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
-		}
+                } else
+			STp->buffer->buffer_bytes = OS_FRAME_SIZE;
 		return 1;
 	}
 	if (STp->buffer->syscall_result) {
@@ -619,8 +619,10 @@
 	if (!SRpnt) return (-EBUSY);
 
 	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
-		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4          &&
-	       (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)         ) {
+	       (( SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4    &&
+		 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)    ) ||
+		( SRpnt->sr_sense_buffer[2]  == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
+		  SRpnt->sr_sense_buffer[13] == 0                                        )  )) {
 #if DEBUG
 	    if (debugging) {
 		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev);
@@ -628,7 +630,7 @@
 		debugging = 0;
 	    }
 #endif
-	    current->state = TASK_INTERRUPTIBLE;
+	    set_current_state(TASK_INTERRUPTIBLE);
 	    schedule_timeout(HZ / 10);
 
 	    memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -656,6 +658,66 @@
 	return 0;
 }
 
+/*
+ * Wait for a tape to be inserted in the unit
+ */
+static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Request  * SRpnt;
+	long		startwait = jiffies;
+#if DEBUG
+	int		dbg = debugging;
+	int		dev  = TAPE_NR(STp->devt);
+
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
+	*aSRpnt = SRpnt;
+	if (!SRpnt) return (-EBUSY);
+
+	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
+		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 0x3a       &&
+	        SRpnt->sr_sense_buffer[13] == 0                                             ) {
+#if DEBUG
+	    if (debugging) {
+		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
+		debugging = 0;
+	    }
+#endif
+	    set_current_state(TASK_INTERRUPTIBLE);
+	    schedule_timeout(HZ / 10);
+
+	    memset(cmd, 0, MAX_COMMAND_SIZE);
+	    cmd[0] = TEST_UNIT_READY;
+
+	    SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
+	}
+	*aSRpnt = SRpnt;
+#if DEBUG
+	debugging = dbg;
+#endif
+	if ( STp->buffer->syscall_result     && SRpnt->sr_sense_buffer[2]  != 2 &&
+	     SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev);
+	    printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
+			STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+			SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+	    return 0;
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev);
+#endif
+	return 1;
+}
+
 static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
 {
 	int	retval;
@@ -694,7 +756,7 @@
 		result = osst_write_error_recovery(STp, aSRpnt, 0);
 
 	result |= osst_wait_ready(STp, aSRpnt, 5 * 60);
-	STp->ps[STp->partition].rw = ST_IDLE;
+	STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
 	return (result);
 }
 
@@ -743,7 +805,7 @@
 			notyetprinted--;
 		}
 #endif
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout (HZ / OSST_POLL_PER_SEC);
 	}
 #if DEBUG
@@ -901,6 +963,8 @@
 #endif
 		if ( osst_initiate_read(STp, aSRpnt)
                 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
+			if (STp->raw)
+				return (-EIO);
 			position = osst_get_frame_position(STp, aSRpnt);
 			if (position >= 0xbae && position < 0xbb8)
 				position = 0xbb8;
@@ -966,7 +1030,7 @@
 	if (cnt > 1) {
 		STp->recover_count++;
 		STp->recover_erreg++;
-		printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", 
+		printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", 
 					dev, STp->read_error_frame);
  	}
 	STp->read_count++;
@@ -1523,7 +1587,10 @@
 			retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
 		else
 			retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
-		printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" ");
+		printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev,
+			       	retval?"E"    :"I",
+			       	retval?""     :"Don't worry, ",
+			       	retval?" not ":" ");
 		break;
 	   case OS_WRITE_LAST_MARK:
 		printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev);
@@ -1594,7 +1661,7 @@
 			       mt_count, last_mark_ppos);
 #endif
 		if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
-			osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 				printk(OSST_DEB_MSG 
@@ -1626,7 +1693,7 @@
 #if DEBUG
 		printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos);
 #endif
-		osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
+		osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
 		cnt++;
 		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
@@ -1753,7 +1820,7 @@
 #endif
 			return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 		} else {
-			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 				printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
@@ -1793,7 +1860,7 @@
 #endif
 					return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 				}
-				osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0);
+				osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
 				if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 					printk(OSST_DEB_MSG
@@ -1825,7 +1892,7 @@
 #if DEBUG
 			else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos);
 #endif
-			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
 			cnt++;
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
@@ -2462,7 +2529,7 @@
 	}
 
 #if DEBUG
-	printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev);
+	printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev);
 	 /*
 	 * In debug mode, we want to see as many errors as possible
 	 * to test the error recovery mechanism.
@@ -3400,6 +3467,7 @@
 		if (retval)
 			goto out;
 		STps->rw = ST_IDLE;
+		/* FIXME -- this may leave the tape without EOD and up2date headers */
 	}
 
 	if ((count % STp->block_size) != 0) {
@@ -3812,6 +3880,10 @@
 			ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
 		 else
 			ioctl_result = 0;
+#if DEBUG
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg);
+#endif
 		 for (i=0; i<arg; i++)
 			ioctl_result |= osst_write_filemark(STp, &SRpnt);
 		 if (fileno >= 0) fileno += arg;
@@ -3831,14 +3903,9 @@
 		 cmd[4] = arg;
 		 timeout = STp->timeout;
 #if DEBUG
-		 if (debugging) {
-			if (cmd_in == MTWEOF)
-			   printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev,
-				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-			else
-			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev,
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev,
 				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-		 }
 #endif
 		 if (fileno >= 0)
 			fileno += arg;
@@ -3851,8 +3918,12 @@
 	 case MTRETEN:
 		 cmd[0] = START_STOP;
 		 cmd[1] = 1;			/* Don't wait for completion */
-		 if (cmd_in == MTLOAD)
+		 if (cmd_in == MTLOAD) {
+		     if (STp->ready == ST_NO_TAPE)
+			 cmd[4] = 4;		/* open tray */
+		      else
 			 cmd[4] = 1;		/* load */
+		 }
 		 if (cmd_in == MTRETEN)
 			 cmd[4] = 3;		/* retension then mount */
 		 if (cmd_in == MTOFFL)
@@ -3991,7 +4062,7 @@
 		printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
 #endif
 
-	if (!ioctl_result) {
+	if (!ioctl_result) {				/* success */
 
 		if (cmd_in == MTFSFM) {
 			 fileno--;
@@ -4068,6 +4139,8 @@
 		if (cmd_in == MTLOCK)
 			STp->door_locked = ST_LOCK_FAILS;
 
+		if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
+			ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60);
 	}
 	*aSRpnt = SRpnt;
 
@@ -4108,6 +4181,7 @@
 		 __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
 	if (osst_template.module)
 		 __MOD_INC_USE_COUNT(osst_template.module);
+	STp->device->access_count++;
 
 	if (mode != STp->current_mode) {
 #if DEBUG
@@ -4124,6 +4198,8 @@
 	STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
 
 	STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0;
+	if (STp->raw)
+		STp->header_ok = 0;
 
 	/* Allocate a buffer for this user */
 	need_dma_buffer = STp->restr_dma;
@@ -4214,7 +4290,7 @@
 			STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
 		for (i=0; i < ST_NBR_PARTITIONS; i++) {
 			STps = &(STp->ps[i]);
-			STps->rw = ST_IDLE;			/* FIXME - seems to be redundant... */
+			STps->rw = ST_IDLE;		/* FIXME - seems to be redundant... */
 			STps->eof = ST_NOEOF;
 			STps->at_sm = 0;
 			STps->last_block_valid = FALSE;
@@ -4262,8 +4338,8 @@
 					STp->door_locked = ST_LOCKED_AUTO;
 			}
 			if (!STp->frame_in_buffer) {
-				STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
-					    (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
+				STp->block_size = (STm->default_blksize > 0) ?
+							STm->default_blksize : OS_DATA_SIZE;
 				STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
 			}
 			STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
@@ -4356,8 +4432,6 @@
 		return 0;
 	}
 
-	STp->min_block = STp->max_block = (-1);
-
 	osst_configure_onstream(STp, &SRpnt);
 
 /*	STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
@@ -4384,11 +4458,9 @@
 	} else
 		STp->buffer->aux = NULL; /* this had better never happen! */
 
-	STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
+	STp->block_size = STp->raw ? OS_FRAME_SIZE : (
 			     (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
-	STp->min_block  = 512;
-	STp->max_block  = OS_DATA_SIZE;
-	STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
+	STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
 	STp->buffer->buffer_bytes  =
 	STp->buffer->read_pointer  =
 	STp->frame_in_buffer       = 0;
@@ -4446,6 +4518,8 @@
 		STp->buffer = NULL;
 	}
 	STp->in_use = 0;
+	STp->header_ok = 0;
+	STp->device->access_count--;
 
 	if (STp->device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
@@ -4482,7 +4556,7 @@
 		if (result != 0 && result != (-ENOSPC))
 			goto out;
 	}
-	if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+	if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) {
 
 #if DEBUG
 		if (debugging) {
@@ -4492,16 +4566,17 @@
 					       dev, STp->nbr_waits, STp->nbr_finished);
 		}
 #endif
+		if (STp->write_type != OS_WRITE_NEW_MARK) {
+			/* true unless the user wrote the filemark for us */
+			result = osst_flush_drive_buffer(STp, &SRpnt);
+			if (result < 0) goto out;
+			result = osst_write_filemark(STp, &SRpnt);
+			if (result < 0) goto out;
 
-		result = osst_flush_drive_buffer(STp, &SRpnt);
-		if (result < 0) goto out;
-		result = osst_write_filemark(STp, &SRpnt);
-		if (result < 0) goto out;
-
-		if (STps->drv_file >= 0)
-			STps->drv_file++ ;
-		STps->drv_block = 0;
-
+			if (STps->drv_file >= 0)
+				STps->drv_file++ ;
+			STps->drv_block = 0;
+		}
 		result = osst_write_eod(STp, &SRpnt);
 		osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
 
@@ -4585,7 +4660,12 @@
 	if (STp->buffer != NULL)
 		STp->buffer->in_use = 0;
 
+	if (STp->raw)
+		STp->header_ok = 0;
+
 	STp->in_use = 0;
+	STp->device->access_count--;
+
 	if (STp->device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
 	if(osst_template.module)
@@ -4635,7 +4715,10 @@
 
 	cmd_type = _IOC_TYPE(cmd_in);
 	cmd_nr   = _IOC_NR(cmd_in);
-
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev,
+			    cmd_type, cmd_nr, STp->raw?"raw":"normal");
+#endif
 	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
 		struct mtop mtc;
 
@@ -4718,8 +4801,8 @@
 			}
 		}
 
-		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
-		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
+		if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
+		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
 		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
 			STps->rw = ST_IDLE;  /* Prevent automatic WEOF and fsf */
 
@@ -4771,7 +4854,10 @@
 	 	}
 
 		if (mtc.mt_op == MTSEEK) {
-			i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
+			if (STp->raw)
+				i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
+			else
+				i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
 			if (!STp->can_partitions)
 				STp->ps[0].rw = ST_IDLE;
 			retval = i;
@@ -4876,7 +4962,10 @@
 			retval = (-EINVAL);
 			goto out;
 		}
-		blk = osst_get_sector(STp, &SRpnt);
+		if (STp->raw)
+			blk = osst_get_frame_position(STp, &SRpnt);
+		else
+			blk = osst_get_sector(STp, &SRpnt);
 		if (blk < 0) {
 			retval = blk;
 			goto out;
@@ -4971,7 +5060,7 @@
 				tb = NULL;
 				break;
 			    }
-			    tb->sg[segs].page = NULL;
+                            tb->sg[segs].page = NULL;
 			    tb->sg[segs].length = b_size;
 			    got += b_size;
 			    segs++;
@@ -5423,6 +5512,8 @@
 	tpnt->partition = 0;
 	tpnt->new_partition = 0;
 	tpnt->nbr_partitions = 0;
+	tpnt->min_block = 512;
+	tpnt->max_block = OS_DATA_SIZE;
 	tpnt->timeout = OSST_TIMEOUT;
 	tpnt->long_timeout = OSST_LONG_TIMEOUT;
 
@@ -5462,6 +5553,7 @@
 
 	tpnt->current_mode = 0;
 	tpnt->modes[0].defined = TRUE;
+	tpnt->modes[2].defined = TRUE;
 	tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
 	init_MUTEX(&tpnt->lock);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/osst.h linux/drivers/scsi/osst.h
--- linux-2.4.16/drivers/scsi/osst.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/osst.h	Tue Dec  4 19:25:31 2001
@@ -1,5 +1,5 @@
 /*
- *	$Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $
+ *	$Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $
  */
 
 #include <asm/byteorder.h>
@@ -638,3 +638,5 @@
 #define OS_WRITE_HEADER    4
 #define OS_WRITE_FILLER    5
 
+/* Additional rw state */
+#define OS_WRITING_COMPLETE 3
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c
--- linux-2.4.16/drivers/scsi/pas16.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/pas16.c	Sun Dec  9 23:03:58 2001
@@ -1,7 +1,7 @@
 #define AUTOSENSE
 #define PSEUDO_DMA
-#define FOO
-#define UNSAFE  /* Not unsafe for PAS16 -- use it */
+#define BOARD_REQUIRES_NO_UDELAY	/* PAS16 needs no I/O recovery delays */
+#define UNSAFE				/* Not unsafe for PAS16 -- use it */
 
 /*
  * This driver adapted from Drew Eckhardt's Trantor T128 driver
@@ -52,8 +52,6 @@
  *
  * PARITY - enable parity checking.  Not supported.
  * 
- * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
- *
  * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  This
  *	    parameter comes from the NCR5380 code.  It is NOT unsafe with
  *	    the PAS16 and you should use it.  If you don't you will have
@@ -62,8 +60,6 @@
  *	    want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
  *	    twiddle with the transfer size in the high level code.
  *
- * USLEEP - enable support for devices that don't disconnect.  Untested.
- *
  * The card is detected and initialized in one of several ways : 
  * 1.  Autoprobe (default) - There are many different models of
  *     the Pro Audio Spectrum/Studio 16, and I only have one of
@@ -109,7 +105,7 @@
  *
  *   (IRQ_AUTO == 254, IRQ_NONE == 255 in NCR5380.h)
  */
- 
+
 #include <linux/module.h>
 
 #include <asm/system.h>
@@ -133,467 +129,402 @@
 static int pas_wmaxi = 0;
 static unsigned short pas16_addr = 0;
 static int pas16_irq = 0;
- 
 
-int scsi_irq_translate[] =
-	{ 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
+static int scsi_irq_translate[] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
 
 /* The default_irqs array contains values used to set the irq into the
  * board via software (as must be done on newer model boards without
  * irq jumpers on the board).  The first value in the array will be
  * assigned to logical board 0, the next to board 1, etc.
  */
-int default_irqs[] __initdata = 
-	{  PAS16_DEFAULT_BOARD_1_IRQ,
-	   PAS16_DEFAULT_BOARD_2_IRQ,
-	   PAS16_DEFAULT_BOARD_3_IRQ,
-	   PAS16_DEFAULT_BOARD_4_IRQ
-	};
+
+static int default_irqs[] __initdata = {
+	PAS16_DEFAULT_BOARD_1_IRQ,
+	PAS16_DEFAULT_BOARD_2_IRQ,
+	PAS16_DEFAULT_BOARD_3_IRQ,
+	PAS16_DEFAULT_BOARD_4_IRQ
+};
 
 static struct override {
-    unsigned short io_port;
-    int  irq;
-} overrides 
+	unsigned short io_port;
+	int irq;
+} overrides
 #ifdef PAS16_OVERRIDE
-    [] __initdata = PAS16_OVERRIDE;
+[] __initdata = PAS16_OVERRIDE;
 #else
-    [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
-	{0,IRQ_AUTO}};
+[4] __initdata = { 
+	{0, IRQ_AUTO},
+	{0, IRQ_AUTO},
+	{0, IRQ_AUTO},
+	{0, IRQ_AUTO}
+};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
 static struct base {
-    unsigned short io_port;
-    int noauto;
-} bases[] __initdata = 
-	{ {PAS16_DEFAULT_BASE_1, 0},
-	  {PAS16_DEFAULT_BASE_2, 0},
-	  {PAS16_DEFAULT_BASE_3, 0},
-	  {PAS16_DEFAULT_BASE_4, 0}
-	};
+	unsigned short io_port;
+	int noauto;
+} bases[] __initdata = {
+	{PAS16_DEFAULT_BASE_1, 0},
+	{PAS16_DEFAULT_BASE_2, 0},
+	{PAS16_DEFAULT_BASE_3, 0},
+	{PAS16_DEFAULT_BASE_4, 0}
+};
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
-unsigned short  pas16_offset[ 8 ] =
-    {
-	0x1c00,    /* OUTPUT_DATA_REG */
-	0x1c01,    /* INITIATOR_COMMAND_REG */
-	0x1c02,    /* MODE_REG */
-	0x1c03,    /* TARGET_COMMAND_REG */
-	0x3c00,    /* STATUS_REG ro, SELECT_ENABLE_REG wo */
-	0x3c01,    /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
-	0x3c02,    /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
-		    * START_DMA_TARGET_RECEIVE_REG wo
-		    */
-	0x3c03,    /* RESET_PARITY_INTERRUPT_REG ro,
-		    * START_DMA_INITIATOR_RECEIVE_REG wo
-		    */
-    };
+unsigned short pas16_offset[8] = {
+	0x1c00,			/* OUTPUT_DATA_REG */
+	0x1c01,			/* INITIATOR_COMMAND_REG */
+	0x1c02,			/* MODE_REG */
+	0x1c03,			/* TARGET_COMMAND_REG */
+	0x3c00,			/* STATUS_REG ro, SELECT_ENABLE_REG wo */
+	0x3c01,			/* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
+	0x3c02,			/* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
+				 * START_DMA_TARGET_RECEIVE_REG wo
+				 */
+	0x3c03,			/* RESET_PARITY_INTERRUPT_REG ro,
+				 * START_DMA_INITIATOR_RECEIVE_REG wo
+				 */
+};
 /*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
- where something crashed or gets stuck at */
-/* 1 = blue
- 2 = green
- 3 = cyan
- 4 = red
- 5 = magenta
- 6 = yellow
- 7 = white
-*/
-#if 1
-#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
-
 
-/*
- * Function : enable_board( int  board_num, unsigned short port )
- *
- * Purpose :  set address in new model board
- *
- * Inputs : board_num - logical board number 0-3, port - base address
+/**
+ * 	enable_board	-	enable a pas16 board
+ *	@board_num: logical board id
+ *	@port: port to assign it
  *
+ *	Sets the address on new model PAS16 hardware
  */
 
-static void __init
-	enable_board( int  board_num,  unsigned short port )
+static void __init enable_board(int board_num, unsigned short port)
 {
-    outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
-    outb( port >> 2, MASTER_ADDRESS_PTR );
+	outb(0xbc + board_num, MASTER_ADDRESS_PTR);
+	outb(port >> 2, MASTER_ADDRESS_PTR);
 }
 
-
-
-/*
- * Function : init_board( unsigned short port, int irq )
- *
- * Purpose :  Set the board up to handle the SCSI interface
- *
- * Inputs : port - base address of the board,
- *	    irq - irq to assign to the SCSI port
- *	    force_irq - set it even if it conflicts with sound driver
+/**
+ *	init_board	-	set up board
+ *	@port: board address
+ *	@irq: interrupt line
+ *	@force_irq: if true allow scsi/audio on the same int
  *
+ *	Set the board up to handle the SCSI interface
  */
 
-static void __init 
-	init_board( unsigned short io_port, int irq, int force_irq )
+static void __init init_board(unsigned short io_port, int irq, int force_irq)
 {
-	unsigned int	tmp;
-	unsigned int	pas_irq_code;
+	unsigned int tmp;
+	unsigned int pas_irq_code;
 
 	/* Initialize the SCSI part of the board */
 
-	outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );  /* Timeout counter */
-	outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
-	outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
+	outb(0x30, io_port + P_TIMEOUT_COUNTER_REG);		/* Timeout counter */
+	outb(0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET);	/* Reset TC */
+	outb(0x01, io_port + WAIT_STATE);			/* 1 Wait state */
 
-	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 
-	/* Set the SCSI interrupt pointer without mucking up the sound
-	 * interrupt pointer in the same byte.
+	/*
+	 *	Set the SCSI interrupt pointer without mucking up the sound
+	 *	interrupt pointer in the same byte.
 	 */
-	pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0;
-	tmp = inb( io_port + IO_CONFIG_3 );
-
-	if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0 
-	    && !force_irq )
-	{
-	    printk( "pas16: WARNING: Can't use same irq as sound "
-		    "driver -- interrupts disabled\n" );
-	    /* Set up the drive parameters, disable 5380 interrupts */
-	    outb( 0x4d, io_port + SYS_CONFIG_4 );
-	}
-	else
-	{
-	    tmp = (  tmp & 0x0f ) | ( pas_irq_code << 4 );
-	    outb( tmp, io_port + IO_CONFIG_3 );
+	 
+	pas_irq_code = (irq < 16) ? scsi_irq_translate[irq] : 0;
+	tmp = inb(io_port + IO_CONFIG_3);
+
+	if (((tmp & 0x0f) == pas_irq_code) && pas_irq_code > 0 && !force_irq) {
+		printk(KERN_WARNING "pas16: WARNING: Can't use same irq as sound " "driver -- interrupts disabled\n");
+		/* Set up the drive parameters, disable 5380 interrupts */
+		outb(0x4d, io_port + SYS_CONFIG_4);
+	} else {
+		tmp = (tmp & 0x0f) | (pas_irq_code << 4);
+		outb(tmp, io_port + IO_CONFIG_3);
 
-	    /* Set up the drive parameters and enable 5380 interrupts */
-	    outb( 0x6d, io_port + SYS_CONFIG_4 );
+		/* Set up the drive parameters and enable 5380 interrupts */
+		outb(0x6d, io_port + SYS_CONFIG_4);
 	}
 }
 
 
-/*
- * Function : pas16_hw_detect( unsigned short board_num )
- *
- * Purpose : determine if a pas16 board is present
- * 
- * Inputs : board_num - logical board number ( 0 - 3 )
+/**
+ *	pas16_hw_detect		-	probe for hardware
+ *	@board_num: logical board ID to probe for
  *
- * Returns : 0 if board not found, 1 if found.
+ *	Determine if a pas16 board is present
  */
 
-static int __init 
-     pas16_hw_detect( unsigned short  board_num )
+static int __init pas16_hw_detect(unsigned short board_num)
 {
-    unsigned char	board_rev, tmp;
-    unsigned short	io_port = bases[ board_num ].io_port;
+	unsigned char board_rev, tmp;
+	unsigned short io_port = bases[board_num].io_port;
 
-    /* See if we can find a PAS16 board at the address associated
-     * with this logical board number.
-     */
-
-    /* First, attempt to take a newer model board out of reset and
-     * give it a base address.  This shouldn't affect older boards.
-     */
-    enable_board( board_num, io_port );
+	/* See if we can find a PAS16 board at the address associated
+	 * with this logical board number.
+	 */
 
-    /* Now see if it looks like a PAS16 board */
-    board_rev = inb( io_port + PCB_CONFIG );
+	/* First, attempt to take a newer model board out of reset and
+	 * give it a base address.  This shouldn't affect older boards.
+	 */
+	enable_board(board_num, io_port);
 
-    if( board_rev == 0xff )
-	return 0;
+	/* Now see if it looks like a PAS16 board */
+	board_rev = inb(io_port + PCB_CONFIG);
 
-    tmp = board_rev ^ 0xe0;
+	if (board_rev == 0xff)
+		return 0;
 
-    outb( tmp, io_port + PCB_CONFIG );
-    tmp = inb( io_port + PCB_CONFIG );
-    outb( board_rev, io_port + PCB_CONFIG );
+	tmp = board_rev ^ 0xe0;
 
-    if( board_rev != tmp ) 	/* Not a PAS-16 */
-	return 0;
+	outb(tmp, io_port + PCB_CONFIG);
+	tmp = inb(io_port + PCB_CONFIG);
+	outb(board_rev, io_port + PCB_CONFIG);
 
-    if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) 
-	return 0;  	/* return if no SCSI interface found */
+	if (board_rev != tmp)	/* Not a PAS-16 */
+		return 0;
 
-    /* Mediavision has some new model boards that return ID bits
-     * that indicate a SCSI interface, but they're not (LMS).  We'll
-     * put in an additional test to try to weed them out.
-     */
-
-    outb( 0x01, io_port + WAIT_STATE ); 	/* 1 Wait state */
-    NCR5380_write( MODE_REG, 0x20 );		/* Is it really SCSI? */
-    if( NCR5380_read( MODE_REG ) != 0x20 )	/* Write to a reg.    */
-	return 0;				/* and try to read    */
-    NCR5380_write( MODE_REG, 0x00 );		/* it back.	      */
-    if( NCR5380_read( MODE_REG ) != 0x00 )
-	return 0;
+	if ((inb(io_port + OPERATION_MODE_1) & 0x03) != 0x03)
+		return 0;	/* return if no SCSI interface found */
 
-    return 1;
-}
+	/* Mediavision has some new model boards that return ID bits
+	 * that indicate a SCSI interface, but they're not (LMS).  We'll
+	 * put in an additional test to try to weed them out.
+	 */
 
+	outb(0x01, io_port + WAIT_STATE);		/* 1 Wait state       */
+	NCR5380_write(MODE_REG, 0x20);			/* Is it really SCSI? */
+	if (NCR5380_read(MODE_REG) != 0x20)		/* Write to a reg.    */
+		return 0;				/* and try to read    */
+	NCR5380_write(MODE_REG, 0x00);			/* it back.           */
+	if (NCR5380_read(MODE_REG) != 0x00)
+		return 0;
 
-/*
- * Function : pas16_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
+	return 1;
+}
+
+/**
+ *	pas16_setup	-	parse command line
+ *	@str: command line block
  *
+ *	LILO command line initialization of the overrides array from
+ *	the passed in pas16= options
  */
 
-void __init pas16_setup(char *str, int *ints)
+int __init pas16_setup(char *str, int *ints)
 {
-    static int commandline_current = 0;
-    int i;
-    if (ints[0] != 2) 
-	printk("pas16_setup : usage pas16=io_port,irq\n");
-    else 
-	if (commandline_current < NO_OVERRIDES) {
-	    overrides[commandline_current].io_port = (unsigned short) ints[1];
-	    overrides[commandline_current].irq = ints[2];
-	    for (i = 0; i < NO_BASES; ++i)
-		if (bases[i].io_port == (unsigned short) ints[1]) {
- 		    bases[i].noauto = 1;
-		    break;
-		}
-	    ++commandline_current;
+	static int commandline_current = 0;
+	int i;
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	if (ints[0] != 2)
+		printk(KERN_ERR "pas16_setup : usage pas16=io_port,irq\n");
+	else if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].io_port = (unsigned short) ints[1];
+		overrides[commandline_current].irq = ints[2];
+		for (i = 0; i < NO_BASES; ++i)
+			if (bases[i].io_port == (unsigned short) ints[1]) {
+				bases[i].noauto = 1;
+				break;
+			}
+		++commandline_current;
 	}
+	return 1;
 }
 
-/* 
- * Function : int pas16_detect(Scsi_Host_Template * tpnt)
- *
- * Purpose : detects and initializes PAS16 controllers
- *	that were autoprobed, overridden on the LILO command line, 
- *	or specified at compile time.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- * 
- * Returns : 1 if a host adapter was found, 0 if not.
+__setup("pas16=", pas16_setup);
+
+/**
+ *	pas16_detect	-	detect and configure a pas16
+ *	@tpnt: template
  *
+ *	Detects and initializes PAS16 controllers that were autoprobed, 
+ *	overridden on the LILO command line, or specified at compile time.
  */
 
 int __init pas16_detect(Scsi_Host_Template * tpnt)
 {
-    static int current_override = 0;
-    static unsigned short current_base = 0;
-    struct Scsi_Host *instance;
-    unsigned short io_port;
-    int  count;
+	static int current_override = 0;
+	static unsigned short current_base = 0;
+	struct Scsi_Host *instance;
+	unsigned short io_port;
+	int count;
+
+	tpnt->proc_name = "pas16";
+	tpnt->proc_info = &pas16_proc_info;
+
+	if (pas16_addr != 0) {
+		overrides[0].io_port = pas16_addr;
+		/*
+		 *  This is how we avoid seeing more than
+		 *  one host adapter at the same I/O port.
+		 *  Cribbed shamelessly from pas16_setup().
+		 */
+		for (count = 0; count < NO_BASES; ++count)
+			if (bases[count].io_port == pas16_addr) {
+				bases[count].noauto = 1;
+				break;
+			}
+	}
+	if (pas16_irq != 0)
+		overrides[0].irq = pas16_irq;
 
-    tpnt->proc_name = "pas16";
-    tpnt->proc_info = &pas16_proc_info;
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+		io_port = 0;
 
-    if (pas16_addr != 0) {
-	overrides[0].io_port = pas16_addr;
-	/*
-	*  This is how we avoid seeing more than
-	*  one host adapter at the same I/O port.
-	*  Cribbed shamelessly from pas16_setup().
-	*/
-	for (count = 0; count < NO_BASES; ++count)
-	    if (bases[count].io_port == pas16_addr) {
- 		    bases[count].noauto = 1;
-		    break;
-	}
-    }
-    if (pas16_irq != 0)
-	overrides[0].irq = pas16_irq;
-
-    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
-	io_port = 0;
-
-	if (overrides[current_override].io_port)
-	{
-	    io_port = overrides[current_override].io_port;
-	    enable_board( current_override, io_port );
-	    init_board( io_port, overrides[current_override].irq, 1 );
-	}
-	else
-	    for (; !io_port && (current_base < NO_BASES); ++current_base) {
-#if (PDEBUG & PDEBUG_INIT)
-    printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
-#endif
-		if ( !bases[current_base].noauto &&
-		     pas16_hw_detect( current_base ) ){
-			io_port = bases[current_base].io_port;
-			init_board( io_port, default_irqs[ current_base ], 0 ); 
-#if (PDEBUG & PDEBUG_INIT)
-			printk("scsi-pas16 : detected board.\n");
-#endif
+		if (overrides[current_override].io_port) {
+			io_port = overrides[current_override].io_port;
+			enable_board(current_override, io_port);
+			init_board(io_port, overrides[current_override].irq, 1);
+		}
+		else
+		{
+			for (; !io_port && (current_base < NO_BASES); ++current_base) {
+				if (!bases[current_base].noauto && pas16_hw_detect(current_base)) {
+					io_port = bases[current_base].io_port;
+					init_board(io_port, default_irqs[current_base], 0);
+				}
+			}
 		}
-    }
 
+		if (!io_port)
+			break;
 
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
-	printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
-#endif
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL)
+			break;
+
+		instance->io_port = io_port;
+
+		NCR5380_init(instance, 0);
+
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
+
+		if (instance->irq != IRQ_NONE)
+			if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
+				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) {
+			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+			/* Disable 5380 interrupts, leave drive params the same */
+			outb(0x4d, io_port + SYS_CONFIG_4);
+			outb((inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3);
+		}
 
-	if (!io_port)
-	    break;
+		printk(KERN_INFO "scsi%d : at 0x%04x", instance->host_no, (int)
+		       instance->io_port);
+		if (instance->irq == IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
 
-	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	if(instance == NULL)
-		break;
-		
-	instance->io_port = io_port;
-
-	NCR5380_init(instance, 0);
-
-	if (overrides[current_override].irq != IRQ_AUTO)
-	    instance->irq = overrides[current_override].irq;
-	else 
-	    instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
-
-	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
-		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
-		    instance->host_no, instance->irq);
-		instance->irq = IRQ_NONE;
-	    } 
-
-	if (instance->irq == IRQ_NONE) {
-	    printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
-	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
-	    /* Disable 5380 interrupts, leave drive params the same */
-	    outb( 0x4d, io_port + SYS_CONFIG_4 );
-	    outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
+		++current_override;
+		++count;
 	}
-
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
-	printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
-
-	printk("scsi%d : at 0x%04x", instance->host_no, (int) 
-	    instance->io_port);
-	if (instance->irq == IRQ_NONE)
-	    printk (" interrupts disabled");
-	else 
-	    printk (" irq %d", instance->irq);
-	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
-	    CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
-	NCR5380_print_options(instance);
-	printk("\n");
-
-	++current_override;
-	++count;
-    }
-    return count;
+	return count;
 }
 
-/*
- * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip)
+/**
+ *	pas16_biosparam		-	generate C/H/S data
+ *	@disk: Disk to set up
+ *	@dev: device ident of disk
+ *	@ip: array to return C/H/S mapping
  *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ *	Generates a BIOS / DOS compatible H-C-S mapping for 
  *	the specified device / size.
- * 
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- *	major / minor, ip[] = {heads, sectors, cylinders}  
- *
- * Returns : always 0 (success), initializes ip
- *	
  */
 
-/* 
- * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
- */
-
-int pas16_biosparam(Disk * disk, kdev_t dev, int * ip)
+int pas16_biosparam(Disk * disk, kdev_t dev, int *ip)
 {
-  int size = disk->capacity;
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;		/* I think I have it as /(32*64) */
-  if( ip[2] > 1024 ) {		/* yes, >, not >= */
-	ip[0]=255;
-	ip[1]=63;
-	ip[2]=size/(63*255);
-	if( ip[2] > 1023 )	/* yes >1023... */
-		ip[2] = 1023;
-  }
+	int size = disk->capacity;
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;	/* I think I have it as /(32*64) */
+	if (ip[2] > 1024) {	/* yes, >, not >= */
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (63 * 255);
+		if (ip[2] > 1023)	/* yes >1023... */
+			ip[2] = 1023;
+	}
 
-  return 0;
+	return 0;
 }
 
-/*
- * Function : int NCR5380_pread (struct Scsi_Host *instance, 
- *	unsigned char *dst, int len)
- *
- * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 
- *	dst
- * 
- * Inputs : dst = destination, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog 
- * 	timeout.
+/**
+ *	NCR5380_pread 		-	pseudo DMA read
+ *	@instance: board to read from
+ *	@dst: destination for data
+ *	@len: expected/max block length
+ *
+ *	Fast 5380 pseudo-dma read function, transfers len bytes to 
+ *	dst. Unlike most boards the PAS has IRQs enabled here, which
+ *	helps no end.
  */
 
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
-    int len) {
-    register unsigned char  *d = dst;
-    register unsigned short reg = (unsigned short) (instance->io_port + 
-	P_DATA_REG_OFFSET);
-    register int i = len;
-    int ii = 0;
-
-    while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
-	 ++ii;
-
-    insb( reg, d, i );
-
-    if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
-	outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
-	printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
-	    instance->host_no);
-	return -1;
-    }
-   if (ii > pas_maxi)
-      pas_maxi = ii;
-    return 0;
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+	unsigned char *d = dst;
+	unsigned short reg = (unsigned short) (instance->io_port + P_DATA_REG_OFFSET);
+	int i = len;
+	int ii = 0;
+
+	while (!(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY))
+		++ii;
+
+	insb(reg, d, i);
+
+	if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
+		outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+		printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pread()\n", instance->host_no);
+		return -1;
+	}
+	if (ii > pas_maxi)
+		pas_maxi = ii;
+	return 0;
 }
 
-/*
- * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
- *	unsigned char *src, int len)
- *
- * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
- *	src
- * 
- * Inputs : src = source, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog 
- * 	timeout.
+/**
+ *	NCR5380_pwrite 		-	pseudo DMA write
+ *	@instance: board to write to
+ *	@src: source for data
+ *	@len: expected/max block length
+ *
+ *	Fast 5380 pseudo-dma write function, transfers len bytes from
+ *	src. Unlike most boards the PAS has IRQs enabled here, which
+ *	helps no end.
  */
 
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
-    int len) {
-    register unsigned char *s = src;
-    register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
-    register int i = len;
-    int ii = 0;
-
-    while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
-	 ++ii;
- 
-    outsb( reg, s, i );
-
-    if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
-	outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
-	printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
-	    instance->host_no);
-	return -1;
-    }
-    if (ii > pas_maxi)
-	 pas_wmaxi = ii;
-    return 0;
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+	unsigned char *s = src;
+	unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
+	int i = len;
+	int ii = 0;
+
+	while (!((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY))
+		++ii;
+
+	outsb(reg, s, i);
+
+	if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
+		outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+		printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pwrite()\n", instance->host_no);
+		return -1;
+	}
+	if (ii > pas_maxi)
+		pas_wmaxi = ii;
+	return 0;
 }
 
 #include "NCR5380.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c
--- linux-2.4.16/drivers/scsi/pcmcia/aha152x_stub.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/pcmcia/aha152x_stub.c	Tue Dec  4 19:25:31 2001
@@ -5,7 +5,7 @@
     This driver supports the Adaptec AHA-1460, the New Media Bus
     Toaster, and the New Media Toast & Jam.
     
-    aha152x_cs.c 1.54 2000/06/12 21:27:25
+    aha152x_cs.c 1.58 2001/10/13 00:08:51
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -22,8 +22,8 @@
     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
+    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
@@ -57,42 +57,39 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Adaptec AHA152x-compatible PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
 
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
 static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
 
-/* SCSI bus setup options */
-static int host_id = 7;
-static int reconnect = 1;
-static int parity = 1;
-static int synchronous = 0;
-static int reset_delay = 100;
-static int ext_trans = 0;
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(host_id, "i");
-MODULE_PARM(reconnect, "i");
-MODULE_PARM(parity, "i");
-MODULE_PARM(synchronous, "i");
-MODULE_PARM(reset_delay, "i");
-MODULE_PARM(ext_trans, "i");
+INT_MODULE_PARM(irq_mask,	0xdeb8);
+INT_MODULE_PARM(host_id,	7);
+INT_MODULE_PARM(reconnect,	1);
+INT_MODULE_PARM(parity,		1);
+INT_MODULE_PARM(synchronous,	0);
+INT_MODULE_PARM(reset_delay,	100);
+INT_MODULE_PARM(ext_trans,	0);
 
-MODULE_LICENSE("Dual MPL/GPL");
+#ifdef AHA152X_DEBUG
+INT_MODULE_PARM(debug,		0);
+#endif
+
+#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 =
+"aha152x_cs.c 1.58 2001/10/13 00:08:51 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -277,7 +274,6 @@
     release_region(link->io.BasePort1, link->io.NumPorts1);
     
     /* Set configuration options for the aha152x driver */
-    ints[0] = 7;
     ints[1] = link->io.BasePort1;
     ints[2] = link->irq.AssignedIRQ;
     ints[3] = host_id;
@@ -285,9 +281,13 @@
     ints[5] = parity;
     ints[6] = synchronous;
     ints[7] = reset_delay;
-    if (ext_trans) {
-	ints[8] = ext_trans; ints[0] = 8;
-    }
+    ints[8] = ext_trans;
+#ifdef AHA152X_DEBUG
+    ints[9] = debug;
+    ints[0] = 9;
+#else
+    ints[0] = 8;
+#endif
     aha152x_setup("PCMCIA setup", ints);
     
     scsi_register_module(MODULE_SCSI_HA, &driver_template);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c
--- linux-2.4.16/drivers/scsi/pcmcia/fdomain_stub.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/pcmcia/fdomain_stub.c	Tue Dec  4 19:25:31 2001
@@ -2,7 +2,7 @@
 
     A driver for Future Domain-compatible PCMCIA SCSI cards
 
-    fdomain_cs.c 1.43 2000/06/12 21:27:25
+    fdomain_cs.c 1.47 2001/10/13 00:08:52
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     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
+    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
@@ -54,27 +54,30 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
 
+#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 =
+"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
 /*====================================================================*/
 
 typedef struct scsi_info_t {
@@ -212,6 +215,7 @@
     u_char tuple_data[64];
     Scsi_Device *dev;
     dev_node_t *node, **tail;
+    char str[16];
     struct Scsi_Host *host;
 
     DEBUG(0, "fdomain_config(0x%p)\n", link);
@@ -252,7 +256,8 @@
     ints[0] = 2;
     ints[1] = link->io.BasePort1;
     ints[2] = link->irq.AssignedIRQ;
-    fdomain_setup("PCMCIA setup", ints);
+    sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
+    fdomain_setup(str, ints);
     
     scsi_register_module(MODULE_SCSI_HA, &driver_template);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c
--- linux-2.4.16/drivers/scsi/pcmcia/qlogic_stub.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/pcmcia/qlogic_stub.c	Tue Dec  4 19:25:31 2001
@@ -2,7 +2,7 @@
 
     A driver for the Qlogic SCSI card
 
-    qlogic_cs.c 1.79 2000/06/12 21:27:26
+    qlogic_cs.c 1.83 2001/10/13 00:08:53
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     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
+    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
@@ -40,6 +40,7 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
+#include <asm/byteorder.h>
 #include <scsi/scsi.h>
 #include <linux/major.h>
 #include <linux/blk.h>
@@ -61,26 +62,29 @@
 
 extern void qlogicfas_preset(int port, int irq);
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Qlogic PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
+
+#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 =
+"qlogic_cs.c 1.83 2001/10/13 00:08:53 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- linux-2.4.16/drivers/scsi/scsi.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/scsi.c	Thu Dec  6 16:09:32 2001
@@ -769,11 +769,13 @@
  		  int timeout, int retries)
 {
 	DECLARE_COMPLETION(wait);
+	request_queue_t *q = &SRpnt->sr_device->request_queue;
 	
 	SRpnt->sr_request.waiting = &wait;
 	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
 	scsi_do_req (SRpnt, (void *) cmnd,
 		buffer, bufflen, scsi_wait_done, timeout, retries);
+	generic_unplug_device(q);
 	wait_for_completion(&wait);
 	SRpnt->sr_request.waiting = NULL;
 	if( SRpnt->sr_command != NULL )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- linux-2.4.16/drivers/scsi/scsi_debug.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/scsi_debug.c	Tue Dec  4 19:25:31 2001
@@ -653,7 +653,6 @@
 
 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
 {
-	int size = disk->capacity;
 	info[0] = N_HEAD;
 	info[1] = N_SECTOR;
 	info[2] = N_CYLINDER;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- linux-2.4.16/drivers/scsi/scsi_scan.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/scsi_scan.c	Fri Dec  7 19:50:46 2001
@@ -155,11 +155,14 @@
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN},     // Chaparral G7324 RAID
+	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
 	{"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN},
 	{"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN},
 	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
 	{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
 	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
+	{"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
+	{"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
 
 	/*
 	 * Must be at end of list...
@@ -500,6 +503,7 @@
 	Scsi_Request * SRpnt;
 	int bflags, type = -1;
 	extern devfs_handle_t scsi_devfs_handle;
+	int scsi_level;
 
 	SDpnt->host = shpnt;
 	SDpnt->id = dev;
@@ -672,6 +676,7 @@
 	    (SDpnt->scsi_level == 1 &&
 	     (scsi_result[3] & 0x0f) == 1))
 		SDpnt->scsi_level++;
+	scsi_level = SDpnt->scsi_level;
 
 	/*
 	 * Accommodate drivers that want to sleep when they should be in a polling
@@ -749,6 +754,7 @@
 	SDpnt->queue_depth = 1;
 	SDpnt->host = shpnt;
 	SDpnt->online = TRUE;
+	SDpnt->scsi_level = scsi_level;
 
 	/*
 	 * Register the queue for the device.  All I/O requests will come
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- linux-2.4.16/drivers/scsi/scsicam.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/scsicam.c	Tue Dec  4 19:25:31 2001
@@ -47,15 +47,7 @@
 	int size = disk->capacity;
 	unsigned long temp_cyl;
 
-	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)))
+	if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
 		return -1;
 
 	/* try to infer mapping from partition table */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- linux-2.4.16/drivers/scsi/sg.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sg.c	Mon Dec 10 18:21:40 2001
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char sg_version_str[] = "Version: 3.1.20 (20010814)";
+ static char sg_version_str[] = "Version: 3.1.22 (20011208)";
 #endif
- static int sg_version_num = 30120; /* 2 digits for each component */
+ static int sg_version_num = 30122; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -82,6 +82,8 @@
 #include <linux/iobuf.h>
 #endif
 
+#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -135,10 +137,10 @@
 typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
 {
     unsigned short k_use_sg;    /* Count of kernel scatter-gather pieces */
-    unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
+    unsigned short sglist_len;  /* size of malloc'd scatter-gather list ++ */
     unsigned bufflen;           /* Size of (aggregate) data buffer */
     unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
-    void * buffer;              /* Data buffer or scatter list,12 bytes each*/
+    void * buffer;              /* Data buffer or scatter list + mem_src_arr */
     struct kiobuf * kiobp;      /* for direct IO information */
     char mapped;                /* indicates kiobp has locked pages */
     char buffer_mem_src;        /* heap whereabouts of 'buffer' */
@@ -181,6 +183,7 @@
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
     char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
+    char mmap_called;   /* 0 -> mmap() never called on this fd */
 } Sg_fd; /* 2760 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
@@ -202,7 +205,8 @@
 static int sg_start_req(Sg_request * srp);
 static void sg_finish_rem_req(Sg_request * srp);
 static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp);
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize);
 static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
 			   Sg_request * srp);
 static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
@@ -232,13 +236,14 @@
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static void sg_clr_srpnt(Scsi_Request * SRpnt);
 static int sg_ms_to_jif(unsigned int msecs);
-static unsigned sg_jif_to_ms(int jifs);
+static inline unsigned sg_jif_to_ms(int jifs);
 static int sg_allow_access(unsigned char opcode, char dev_type);
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
 static Sg_device * sg_get_dev(int dev);
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
@@ -617,6 +622,20 @@
 	sg_remove_request(sfp, srp);
 	return -ENOSYS;
     }
+    if (hp->flags & SG_FLAG_MMAP_IO) {
+    	if (hp->dxfer_len > sfp->reserve.bufflen) {
+	    sg_remove_request(sfp, srp);
+	    return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
+	}
+	if (hp->flags & SG_FLAG_DIRECT_IO) {
+	    sg_remove_request(sfp, srp);
+	    return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
+	}
+	if (sg_res_in_use(sfp)) {
+	    sg_remove_request(sfp, srp);
+	    return -EBUSY;	/* reserve buffer already being used */
+	}
+    }
     timeout = sg_ms_to_jif(srp->header.timeout);
     if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) {
 	sg_remove_request(sfp, srp);
@@ -717,7 +736,9 @@
 		(void *)SRpnt->sr_buffer, hp->dxfer_len,
 		sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES);
     /* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1)
     generic_unplug_device(q);
+#endif
     return 0;
 }
 
@@ -851,7 +872,7 @@
         result = get_user(val, (int *)arg);
         if (result) return result;
         if (val != sfp->reserve.bufflen) {
-            if (sg_res_in_use(sfp))
+            if (sg_res_in_use(sfp) || sfp->mmap_called)
                 return -EBUSY;
             sg_remove_scat(&sfp->reserve);
             sg_build_reserve(sfp, val);
@@ -1032,6 +1053,139 @@
     return (retval < 0) ? retval : 0;
 }
 
+static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+    void * page_ptr;
+    struct page * page;
+    int k, m;
+
+    SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, "
+			   "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); 
+    /* N.B. correction _not_ applied to base page of aech allocation */
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+	    for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+		page_ptr = (unsigned char *)sclp->address + m;
+		page = virt_to_page(page_ptr);
+		if (startFinish)
+		    get_page(page);	/* increment page count */
+		else {
+		    if (page_count(page) > 0)
+			put_page_testzero(page); /* decrement page count */
+		}
+	    }
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+	for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+	    page_ptr = (unsigned char *)rsv_schp->buffer + m;
+	    page = virt_to_page(page_ptr);
+	    if (startFinish)
+		get_page(page);	/* increment page count */
+	    else {
+		if (page_count(page) > 0)
+		    put_page_testzero(page); /* decrement page count */
+	    }
+	}
+    }
+}
+
+static struct page * sg_vma_nopage(struct vm_area_struct *vma, 
+				   unsigned long addr, int unused)
+{
+    Sg_fd * sfp;
+    struct page * page = NOPAGE_SIGBUS;
+    void * page_ptr = NULL;
+    unsigned long offset;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data)))
+	return page;
+    rsv_schp = &sfp->reserve;
+    offset = addr - vma->vm_start;
+    if (offset >= rsv_schp->bufflen)
+	return page;
+    SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", 
+			       offset, rsv_schp->k_use_sg));
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        int k;
+        unsigned long sa = vma->vm_start;
+        unsigned long len;
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+             ++k, ++sclp) {
+            len = vma->vm_end - sa;
+            len = (len < sclp->length) ? len : sclp->length;
+	    if (offset < len) {
+		page_ptr = (unsigned char *)sclp->address + offset;
+		page = virt_to_page(page_ptr);
+		get_page(page);	/* increment page count */
+		break;
+	    }
+            sa += len;
+	    offset -= len;
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+        page_ptr = (unsigned char *)rsv_schp->buffer + offset;
+	page = virt_to_page(page_ptr);
+	get_page(page);	/* increment page count */
+    }
+    return page;
+}
+
+static struct vm_operations_struct sg_mmap_vm_ops = {
+    nopage : sg_vma_nopage,
+};
+
+static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
+{
+    Sg_fd * sfp;
+    unsigned long req_sz = vma->vm_end - vma->vm_start;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data)))
+        return -ENXIO;
+    SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", 
+			       (void *)vma->vm_start, (int)req_sz));
+    if (vma->vm_pgoff)
+    	return -EINVAL;		/* want no offset */
+    rsv_schp = &sfp->reserve;
+    if (req_sz > rsv_schp->bufflen)
+    	return -ENOMEM;		/* cannot map more than reserved buffer */
+
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+    	int k;
+	unsigned long sa = vma->vm_start;
+	unsigned long len;
+	struct scatterlist * sclp = rsv_schp->buffer;
+
+	for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); 
+	     ++k, ++sclp) {
+	    if ((unsigned long)sclp->address & (PAGE_SIZE - 1))
+	    	return -EFAULT;     /* non page aligned memory ?? */
+	    len = vma->vm_end - sa;
+	    len = (len < sclp->length) ? len : sclp->length;
+	    sa += len;
+	}
+    }
+    else { /* reserve buffer is just a single allocation */
+    	if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1))
+	    return -EFAULT;	/* non page aligned memory ?? */
+    }
+    if (0 == sfp->mmap_called) {
+    	sg_rb_correct4mmap(rsv_schp, 1);  /* do only once per fd lifetime */
+	sfp->mmap_called = 1;
+    }
+    vma->vm_flags |= (VM_RESERVED | VM_IO);
+    vma->vm_private_data = sfp;
+    vma->vm_ops = &sg_mmap_vm_ops;
+    return 0;
+}
+
 /* This function is a "bottom half" handler that is called by the
  * mid level when a command is completed (or has failed). */
 static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
@@ -1078,7 +1232,14 @@
     srp->data.sglist_len = SRpnt->sr_sglist_len;
     srp->data.bufflen = SRpnt->sr_bufflen;
     srp->data.buffer = SRpnt->sr_buffer;
-    sg_clr_srpnt(SRpnt);
+    /* now clear out request structure */
+    SRpnt->sr_use_sg = 0;
+    SRpnt->sr_sglist_len = 0;
+    SRpnt->sr_bufflen = 0;
+    SRpnt->sr_buffer = NULL;
+    SRpnt->sr_underflow = 0;
+    SRpnt->sr_request.rq_dev = MKDEV(0, 0);  /* "sg" _disowns_ request blk */
+
     srp->my_cmdp = NULL;
     srp->done = 1;
     read_unlock(&sg_dev_arr_lock);
@@ -1123,14 +1284,15 @@
 	if (NULL == sfp->headrp) {
             SCSI_LOG_TIMEOUT(1,
 		printk("sg...bh: already closed, final cleanup\n"));
-            sg_remove_sfp(sdp, sfp);
+            if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
+		sdp->device->access_count--;
+		if (sdp->device->host->hostt->module)
+		    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+	    }
+	    if (sg_template.module)
+		    __MOD_DEC_USE_COUNT(sg_template.module);
 	    sfp = NULL;
         }
-	sdp->device->access_count--;
-	if (sg_template.module)
-		__MOD_DEC_USE_COUNT(sg_template.module);
-	if (sdp->device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
     }
     else if (srp && srp->orphan) {
 	if (sfp->keep_orphan)
@@ -1154,6 +1316,7 @@
 	poll:		sg_poll,
 	ioctl:		sg_ioctl,
 	open:		sg_open,
+	mmap:		sg_mmap,
 	release:	sg_release,
 	fasync:		sg_fasync,
 };
@@ -1178,7 +1341,7 @@
     if(!sg_registered) {
 	if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
         {
-            printk("Unable to get major %d for generic SCSI device\n",
+            printk(KERN_ERR "Unable to get major %d for generic SCSI device\n",
                    SCSI_GENERIC_MAJOR);
 	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
             return 1;
@@ -1191,7 +1354,7 @@
     sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 
     					sizeof(Sg_device *), GFP_ATOMIC);
     if (NULL == sg_dev_arr) {
-        printk("sg_init: no space for sg_dev_arr\n");
+        printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
         return 1;
     }
@@ -1214,8 +1377,8 @@
 	    sg_big_buff = tmp;
 	return 1;
     } else {
-	printk("sg_def_reserved_size : usage sg_def_reserved_size=n "
-	       "(n could be 65536, 131072 or 262144)\n");
+	printk(KERN_WARNING "sg_def_reserved_size : usage "
+	    "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
 	return 0;
     }
 }
@@ -1240,7 +1403,7 @@
 	if (NULL == tmp_da) {
 	    scsidp->attached--;
 	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	    printk("sg_attach: device array cannot be resized\n");
+	    printk(KERN_ERR "sg_attach: device array cannot be resized\n");
 	    return 1;
 	}
 	memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
@@ -1255,7 +1418,7 @@
     if (k > MINORMASK) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk("Unable to attach sg device <%d, %d, %d, %d>"
+	printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>"
 	       " type=%d, minor number exceed %d\n", scsidp->host->host_no, 
 	       scsidp->channel, scsidp->id, scsidp->lun, scsidp->type,
 	       MINORMASK);
@@ -1268,7 +1431,7 @@
     if (NULL == sdp) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk("sg_attach: Sg_device cannot be allocated\n");
+	printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
 	return 1;
     }
 
@@ -1295,8 +1458,8 @@
 	case TYPE_WORM:
 	case TYPE_TAPE: break;
 	default:
-	    printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
-		   " lun %d,  type %d\n", k, scsidp->host->host_no, 
+	    printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel"
+	    	   " %d, id %d, lun %d,  type %d\n", k, scsidp->host->host_no, 
 		   scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
     }
     return 0;
@@ -1373,7 +1536,10 @@
 
 MODULE_AUTHOR("Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI generic (sg) driver");
+
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
+#endif
 
 MODULE_PARM(def_reserved_size, "i");
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
@@ -1420,9 +1586,8 @@
 	if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
 	    return res;
     }
-    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) {
+    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
 	sg_link_reserve(sfp, srp, dxfer_len);
-    }
     else {
 	res = sg_build_indi(req_schp, sfp, dxfer_len);
         if (res) {
@@ -1448,23 +1613,24 @@
     sg_remove_request(sfp, srp);
 }
 
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize)
 {
     int mem_src, ret_sz;
-    int sg_bufflen = PAGE_SIZE;
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+    /* scatter gather array, followed by mem_src_arr (array of chars) */
+    int sg_bufflen = tablesize * elem_sz;
+    int mx_sc_elems = tablesize;
 
     mem_src = SG_HEAP_KMAL;
-    schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen,
-						   &ret_sz, &mem_src);
-    schp->buffer_mem_src = (char)mem_src;
+    schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src);
     if (! schp->buffer)
 	return -ENOMEM;
     else if (ret_sz != sg_bufflen) {
 	sg_bufflen = ret_sz;
-	mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+	mx_sc_elems = sg_bufflen / elem_sz;
     }
+    schp->buffer_mem_src = (char)mem_src;
     schp->sglist_len = sg_bufflen;
     memset(schp->buffer, 0, sg_bufflen);
     return mx_sc_elems; /* number of scat_gath elements allocated */
@@ -1473,13 +1639,15 @@
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
 {
 #ifdef SG_ALLOW_DIO_CODE
+    int nbhs = 0;
+
     if (schp && schp->kiobp) {
 	if (schp->mapped) {
 	    unmap_kiobuf(schp->kiobp);
 	    schp->mapped = 0;
 	}
 	if (free_also) {
-	    free_kiovec(1, &schp->kiobp);
+	    sg_free_kiovec(1, &schp->kiobp, &nbhs);
 	    schp->kiobp = NULL;
 	}
     }
@@ -1497,10 +1665,12 @@
     sg_io_hdr_t * hp = &srp->header;
     Sg_scatter_hold * schp = &srp->data;
     int sg_tablesize = sfp->parentdp->sg_tablesize;
+    int nbhs = 0;
 
-    res = alloc_kiovec(1, &schp->kiobp);
+    res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
     if (0 != res) {
-	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res));
+	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", 
+			 res));
 	return 1;
     }
     res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0,
@@ -1530,7 +1700,7 @@
 	hp->info |= SG_INFO_DIRECT_IO;
 	return 0;
     }
-    mx_sc_elems = sg_build_sgat(schp, sfp);
+    mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
     if (mx_sc_elems <= 1) {
 	sg_unmap_and(schp, 1);
 	sg_remove_scat(schp);
@@ -1538,13 +1708,15 @@
     }
     mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
     for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len;
-	 (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+	 (rem_sz > 0) && (k < mx_sc_elems);
 	 ++k, ++sclp) {
 	offset = (0 == k) ? kp->offset : 0;
 	num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
 						rem_sz;
 	sclp->address = page_address(kp->maplist[k]) + offset;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
 	sclp->page = NULL;
+#endif
 	sclp->length = num;
 	mem_src_arr[k] = SG_USER_MEM;
 	rem_sz -= num;
@@ -1612,14 +1784,14 @@
 	char * mem_src_arr;
 
         /* N.B. ret_sz and mem_src carried into this block ... */
-	mx_sc_elems = sg_build_sgat(schp, sfp);
+	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
 	if (mx_sc_elems < 0)
 	    return mx_sc_elems; /* most likely -ENOMEM */
 	mem_src_arr = schp->buffer +
 		      (mx_sc_elems * sizeof(struct scatterlist));
 
 	for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
-	     (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+	     (rem_sz > 0) && (k < mx_sc_elems);
              ++k, rem_sz -= ret_sz, ++sclp) {
 	    if (first)
                 first = 0;
@@ -1631,7 +1803,9 @@
                     break;
             }
             sclp->address = p;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
 	    sclp->page = NULL;
+#endif
             sclp->length = ret_sz;
 	    mem_src_arr[k] = mem_src;
 
@@ -1667,7 +1841,8 @@
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
 	return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1769,7 +1944,7 @@
 static char * sg_get_sgat_msa(Sg_scatter_hold * schp)
 {
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (schp->sglist_len / elem_sz) - 1;
+    int mx_sc_elems = schp->sglist_len / elem_sz;
     return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);
 }
 
@@ -1789,7 +1964,9 @@
                        k, sclp->address, sclp->length, mem_src));
             sg_free(sclp->address, sclp->length, mem_src);
             sclp->address = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
 	    sclp->page = NULL;
+#endif
             sclp->length = 0;
         }
 	sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
@@ -1817,7 +1994,8 @@
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
 	return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -2192,6 +2370,8 @@
     if (sfp->reserve.bufflen > 0) {
     SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
 	     (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+	if (sfp->mmap_called)
+	    sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */
 	sg_remove_scat(&sfp->reserve);
     }
     sfp->parentdp = NULL;
@@ -2240,7 +2420,7 @@
 	/* MOD_INC's to inhibit unloading sg and associated adapter driver */
 	if (sg_template.module)
 	    __MOD_INC_USE_COUNT(sg_template.module);
-	 if (sdp->device->host->hostt->module)
+	if (sdp->device->host->hostt->module)
 	    __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
         SCSI_LOG_TIMEOUT(1, printk(
           "sg_remove_sfp: worrisome, %d writes pending\n", dirty));
@@ -2315,7 +2495,8 @@
         if (retSzp) *retSzp = resSz;
     }
     else
-        printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz);
+        printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", 
+	       mem_src, rqSz);
     return resp;
 }
 
@@ -2350,7 +2531,7 @@
             if (resp && retSzp) *retSzp = size;
             break;
         case SG_HEAP_KMAL:
-            l_ms = SG_HEAP_PAGE;
+            l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
             if (resp)
                 break;
@@ -2369,6 +2550,15 @@
     return resp;
 }
 
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
+{
+#if SG_NEW_KIOVEC
+    return alloc_kiovec_sz(nr, bufp, szp);
+#else
+    return alloc_kiovec(nr, bufp);
+#endif
+}
+
 static void sg_low_free(char * buff, int size, int mem_src)
 {
     if (! buff) return;
@@ -2396,7 +2586,7 @@
     case SG_USER_MEM:
 	break; /* nothing to do */
     default:
-	printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
+	printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
                mem_src, buff, size);
 	break;
     }
@@ -2412,14 +2602,13 @@
         sg_low_free(buff, size, mem_src);
 }
 
-static void sg_clr_srpnt(Scsi_Request * SRpnt)
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
 {
-    SRpnt->sr_use_sg = 0;
-    SRpnt->sr_sglist_len = 0;
-    SRpnt->sr_bufflen = 0;
-    SRpnt->sr_buffer = NULL;
-    SRpnt->sr_underflow = 0;
-    SRpnt->sr_request.rq_dev = MKDEV(0, 0);  /* "sg" _disowns_ command blk */
+#if SG_NEW_KIOVEC
+    free_kiovec_sz(nr, bufp, szp);
+#else
+    free_kiovec(nr, bufp);
+#endif
 }
 
 static int sg_ms_to_jif(unsigned int msecs)
@@ -2431,7 +2620,7 @@
 					       : (((int)msecs / 1000) * HZ);
 }
 
-static unsigned sg_jif_to_ms(int jifs)
+static inline unsigned sg_jif_to_ms(int jifs)
 {
     if (jifs <= 0)
 	return 0U;
@@ -2481,8 +2670,8 @@
     if (sg_dev_arr && (dev >= 0))
     {
 	read_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if (dev < sg_template.dev_max)
-    	sdp = sg_dev_arr[dev];
+	if (dev < sg_template.dev_max)
+	    sdp = sg_dev_arr[dev];
 	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
     }
     return sdp;
@@ -2675,7 +2864,7 @@
 {
     Sg_device * sdp;
     const sg_io_hdr_t * hp;
-    int j, max_dev;
+    int j, max_dev, new_interface;
 
     if (NULL == sg_dev_arr) {
 	PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
@@ -2722,8 +2911,10 @@
 			   (int)fp->keep_orphan, (int)fp->closed);
 		for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
 		    hp = &srp->header;
+		    new_interface = (hp->interface_id == '\0') ? 0 : 1;
 /* stop indenting so far ... */
-	PRINT_PROC(srp->res_used ? "     rb>> " :
+	PRINT_PROC(srp->res_used ? ((new_interface && 
+	    (SG_FLAG_MMAP_IO & hp->flags)) ? "     mmap>> " : "     rb>> ") :
 	    ((SG_INFO_DIRECT_IO_MASK & hp->info) ? "     dio>> " : "     "));
 	blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen;
 	usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
@@ -2733,8 +2924,8 @@
 	if (srp->done)
 	    PRINT_PROC(" dur=%d", hp->duration);
 	else
-	    PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ?
-			sg_jif_to_ms(fp->timeout) : hp->timeout),
+	    PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout :
+			sg_jif_to_ms(fp->timeout),
 		  sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
 	PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode);
 /* reset indenting */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- linux-2.4.16/drivers/scsi/sym53c8xx.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx.c	Wed Dec  5 20:22:25 2001
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2001  Gerard Roudier <groudier@free.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -32,7 +32,7 @@
 **  The Linux port of the FreeBSD ncr driver has been achieved in 
 **  november 1995 by:
 **
-**          Gerard Roudier              <groudier@club-internet.fr>
+**          Gerard Roudier              <groudier@free.fr>
 **
 **  Being given that this driver originates from the FreeBSD version, and
 **  in order to keep synergy on both, any suggested enhancements and corrections
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h
--- linux-2.4.16/drivers/scsi/sym53c8xx.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx.h	Wed Dec  5 20:22:25 2001
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2001  Gerard Roudier <groudier@free.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -32,7 +32,7 @@
 **  The Linux port of the FreeBSD ncr driver has been achieved in 
 **  november 1995 by:
 **
-**          Gerard Roudier              <groudier@club-internet.fr>
+**          Gerard Roudier              <groudier@free.fr>
 **
 **  Being given that this driver originates from the FreeBSD version, and
 **  in order to keep synergy on both, any suggested enhancements and corrections
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/ChangeLog.txt linux/drivers/scsi/sym53c8xx_2/ChangeLog.txt
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/ChangeLog.txt	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/ChangeLog.txt	Wed Dec  5 20:22:25 2001
@@ -128,3 +128,21 @@
 	* version sym-2.1.16-20011028
 	- Slightly simplify driver configuration.
 	- Prepare a new patch against linux-2.4.13.
+
+Sat Nov 17 10:00 2001 Gerard Roudier 
+	* version sym-2.1.17
+	- Fix a couple of gcc/gcc3 warnings.
+	- Allocate separately from the HCB the array for CCBs hashed by DSA.
+	  All driver memory allocations are now not greater than 1 PAGE 
+	  even on PPC64 / 4KB PAGE surprising setup.
+
+Sat Dec 01 18:00 2001 Gerard Roudier 
+	* version sym-2.1.17a
+	- Use u_long instead of U32 for the IO base cookie. This is more 
+	  consistent with what archs are expecting.
+	- Use MMIO per default for Power PC instead of some fake normal IO,
+	  as Paul Mackerras stated that MMIO works fine now on this arch.
+
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/sym53c8xx.h linux/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Wed Dec  5 20:22:25 2001
@@ -130,17 +130,17 @@
 #if !defined(HOSTS_C)
 
 /*
- *  Use normal IO if configured. Forced for alpha and powerpc.
- *  Powerpc fails copying to on-chip RAM using memcpy_toio().
+ *  Use normal IO if configured.
+ *  Normal IO forced for alpha.
  *  Forced to MMIO for sparc.
  */
 #if defined(__alpha__)
 #define	SYM_CONF_IOMAPPED
-#elif defined(__powerpc__)
-#define	SYM_CONF_IOMAPPED
-#define SYM_OPT_NO_BUS_MEMORY_MAPPING
 #elif defined(__sparc__)
 #undef SYM_CONF_IOMAPPED
+/* #elif defined(__powerpc__) */
+/* #define	SYM_CONF_IOMAPPED */
+/* #define SYM_OPT_NO_BUS_MEMORY_MAPPING */
 #elif defined(CONFIG_SCSI_SYM53C8XX_IOMAPPED)
 #define	SYM_CONF_IOMAPPED
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_glue.c linux/drivers/scsi/sym53c8xx_2/sym_glue.c
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_glue.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym_glue.c	Wed Dec  5 20:22:25 2001
@@ -2456,8 +2456,8 @@
 	u_char pci_fix_up = SYM_SETUP_PCI_FIX_UP;
 	u_char revision;
 	u_int irq;
-	u_long base, base_2, io_port; 
-	u_long base_c, base_2_c; 
+	u_long base, base_2, base_io; 
+	u_long base_c, base_2_c, io_port; 
 	int i;
 	sym_chip *chip;
 
@@ -2474,7 +2474,7 @@
 	device_id = PciDeviceId(pdev);
 	irq	  = PciIrqLine(pdev);
 
-	i = pci_get_base_address(pdev, 0, &io_port);
+	i = pci_get_base_address(pdev, 0, &base_io);
 	io_port = pci_get_base_cookie(pdev, 0);
 
 	base_c = pci_get_base_cookie(pdev, i);
@@ -2492,9 +2492,9 @@
 	/*
 	 *  If user excluded this chip, donnot initialize it.
 	 */
-	if (io_port) {
+	if (base_io) {
 		for (i = 0 ; i < 8 ; i++) {
-			if (sym_driver_setup.excludes[i] == io_port)
+			if (sym_driver_setup.excludes[i] == base_io)
 				return -1;
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_glue.h linux/drivers/scsi/sym53c8xx_2/sym_glue.h
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_glue.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym_glue.h	Wed Dec  5 20:22:25 2001
@@ -77,7 +77,6 @@
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/time.h>
@@ -463,7 +462,7 @@
 
 	vm_offset_t	mmio_va;	/* MMIO kernel virtual address	*/
 	vm_offset_t	ram_va;		/* RAM  kernel virtual address	*/
-	u32		io_port;	/* IO port address		*/
+	u_long		io_port;	/* IO port address cookie	*/
 	u_short		io_ws;		/* IO window size		*/
 	int		irq;		/* IRQ number			*/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_hipd.c linux/drivers/scsi/sym53c8xx_2/sym_hipd.c
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_hipd.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym_hipd.c	Wed Dec  5 20:22:25 2001
@@ -50,7 +50,7 @@
  * SUCH DAMAGE.
  */
 
-#define SYM_DRIVER_NAME	"sym-2.1.16a"
+#define SYM_DRIVER_NAME	"sym-2.1.17a"
 
 #ifdef __FreeBSD__
 #include <dev/sym/sym_glue.h>
@@ -4691,6 +4691,7 @@
 	OUTL_DSP (SCRIPTA_BA (np, clrack));
 	return;
 out_stuck:
+	return;
 }
 
 /*
@@ -5226,6 +5227,7 @@
 
 	return;
 fail:
+	return;
 }
 
 /*
@@ -5788,6 +5790,13 @@
 		goto attach_failed;
 
 	/*
+	 *  Allocate the array of lists of CCBs hashed by DSA.
+	 */
+	np->ccbh = sym_calloc(sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH");
+	if (!np->ccbh)
+		goto attach_failed;
+
+	/*
 	 *  Initialyze the CCB free and busy queues.
 	 */
 	sym_que_init(&np->free_ccbq);
@@ -5978,6 +5987,8 @@
 			sym_mfree_dma(cp, sizeof(*cp), "CCB");
 		}
 	}
+	if (np->ccbh)
+		sym_mfree(np->ccbh, sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH");
 
 	if (np->badluntbl)
 		sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_hipd.h linux/drivers/scsi/sym53c8xx_2/sym_hipd.h
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_hipd.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym_hipd.h	Wed Dec  5 20:22:25 2001
@@ -1068,7 +1068,8 @@
 	/*
 	 *  CCB lists and queue.
 	 */
-	ccb_p ccbh[CCB_HASH_SIZE];	/* CCB hashed by DSA value	*/
+	ccb_p *ccbh;			/* CCBs hashed by DSA value	*/
+					/* CCB_HASH_SIZE lists of CCBs	*/
 	SYM_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
 	SYM_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_nvram.c linux/drivers/scsi/sym53c8xx_2/sym_nvram.c
--- linux-2.4.16/drivers/scsi/sym53c8xx_2/sym_nvram.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym_nvram.c	Wed Dec  5 20:22:25 2001
@@ -505,10 +505,10 @@
 	return retv;
 }
 
-#undef SET_BIT 0
-#undef CLR_BIT 1
-#undef SET_CLK 2
-#undef CLR_CLK 3
+#undef SET_BIT
+#undef CLR_BIT
+#undef SET_CLK
+#undef CLR_CLK
 
 /*
  *  Try reading Symbios NVRAM.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- linux-2.4.16/drivers/scsi/sym53c8xx_comm.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_comm.h	Wed Dec  5 20:22:25 2001
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2001  Gerard Roudier <groudier@free.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -32,7 +32,7 @@
 **  The Linux port of the FreeBSD ncr driver has been achieved in 
 **  november 1995 by:
 **
-**          Gerard Roudier              <groudier@club-internet.fr>
+**          Gerard Roudier              <groudier@free.fr>
 **
 **  Being given that this driver originates from the FreeBSD version, and
 **  in order to keep synergy on both, any suggested enhancements and corrections
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- linux-2.4.16/drivers/scsi/sym53c8xx_defs.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/sym53c8xx_defs.h	Wed Dec  5 20:22:25 2001
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2001  Gerard Roudier <groudier@free.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -32,7 +32,7 @@
 **  The Linux port of the FreeBSD ncr driver has been achieved in 
 **  november 1995 by:
 **
-**          Gerard Roudier              <groudier@club-internet.fr>
+**          Gerard Roudier              <groudier@free.fr>
 **
 **  Being given that this driver originates from the FreeBSD version, and
 **  in order to keep synergy on both, any suggested enhancements and corrections
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- linux-2.4.16/drivers/scsi/t128.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/t128.c	Sun Dec  9 18:26:15 2001
@@ -47,17 +47,12 @@
  * increase compared to polled I/O.
  *
  * PARITY - enable parity checking.  Not supported.
- * 
- * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
- *
  *
  * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
  *          only really want to use this if you're having a problem with
  *          dropped characters during high speed communications, and even
  *          then, you're going to be better off twiddling with transfersize.
  *
- * USLEEP - enable support for devices that don't disconnect.  Untested.
- *
  * The card is detected and initialized in one of several ways : 
  * 1.  Autoprobe (default) - since the board is memory mapped, 
  *     a BIOS signature is scanned for to locate the registers.
@@ -101,10 +96,6 @@
  * 14 10-12
  * 15 9-11
  */
- 
-/*
- * $Log: t128.c,v $
- */
 
 #include <asm/system.h>
 #include <linux/signal.h>
@@ -123,276 +114,252 @@
 #include <linux/module.h>
 
 static struct override {
-    unsigned long address;
-    int irq;
-} overrides 
+	unsigned long address;
+	int irq;
+} overrides
 #ifdef T128_OVERRIDE
-    [] __initdata = T128_OVERRIDE;
+[] __initdata = T128_OVERRIDE;
 #else
-    [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, 
-        {0 ,IRQ_AUTO}, {0, IRQ_AUTO}};
+[4] __initdata = { 
+	{ 0, IRQ_AUTO},
+	{ 0, IRQ_AUTO},
+	{ 0, IRQ_AUTO},
+	{ 0, IRQ_AUTO}
+};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
 static struct base {
-    unsigned int address;
-    int noauto;
+	unsigned int address;
+	int noauto;
 } bases[] __initdata = {
-    { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0}
+	{0xcc000, 0},
+	{0xc8000, 0},
+	{0xdc000, 0},
+	{0xd8000, 0}
 };
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
 static const struct signature {
-    const char *string;
-    int offset;
+	const char *string;
+	int offset;
 } signatures[] __initdata = {
-{"TSROM: SCSI BIOS, Version 1.12", 0x36},
+	{"TSROM: SCSI BIOS, Version 1.12", 0x36},
 };
 
 #define NO_SIGNATURES (sizeof (signatures) /  sizeof (struct signature))
 
-/*
- * Function : t128_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
+/**
+ *	t128_setup
+ *	@str: command line 
  *
+ *	LILO command line initialization of the overrides array,
  */
 
-void __init t128_setup(char *str, int *ints){
-    static int commandline_current = 0;
-    int i;
-    if (ints[0] != 2) 
-	printk("t128_setup : usage t128=address,irq\n");
-    else 
-	if (commandline_current < NO_OVERRIDES) {
-	    overrides[commandline_current].address = ints[1];
-	    overrides[commandline_current].irq = ints[2];
-	    for (i = 0; i < NO_BASES; ++i)
-		if (bases[i].address == ints[1]) {
-		    bases[i].noauto = 1;
-		    break;
-		}
-	    ++commandline_current;
+int __init t128_setup(char *str)
+{
+	static int commandline_current = 0;
+	int ints[10];
+	int i;
+	
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+
+	if (ints[0] != 2)
+		printk(KERN_ERR "t128_setup : usage t128=address,irq\n");
+	else if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].address = ints[1];
+		overrides[commandline_current].irq = ints[2];
+		for (i = 0; i < NO_BASES; ++i)
+			if (bases[i].address == ints[1]) {
+				bases[i].noauto = 1;
+				break;
+			}
+		++commandline_current;
 	}
+	return 1;
 }
 
-/* 
- * Function : int t128_detect(Scsi_Host_Template * tpnt)
+__setup("t128=", t128_setup);
+
+/**
+ *	t128_detect	-	detect controllers
+ *	@tpnt: SCSI template
  *
- * Purpose : detects and initializes T128,T128F, or T228 controllers
+ *	Detects and initializes T128,T128F, or T228 controllers
  *	that were autoprobed, overridden on the LILO command line, 
  *	or specified at compile time.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- * 
- * Returns : 1 if a host adapter was found, 0 if not.
- *
  */
 
-int __init t128_detect(Scsi_Host_Template * tpnt){
-    static int current_override = 0, current_base = 0;
-    struct Scsi_Host *instance;
-    unsigned long base;
-    int sig, count;
-
-    tpnt->proc_name = "t128";
-    tpnt->proc_info = &t128_proc_info;
-
-    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
-	base = 0;
-
-	if (overrides[current_override].address)
-	    base = overrides[current_override].address;
-	else 
-	    for (; !base && (current_base < NO_BASES); ++current_base) {
-#if (TDEBUG & TDEBUG_INIT)
-    printk("scsi-t128 : probing address %08x\n", bases[current_base].address);
-#endif
-		for (sig = 0; sig < NO_SIGNATURES; ++sig) 
-		    if (!bases[current_base].noauto && 
-			isa_check_signature(bases[current_base].address +
-					signatures[sig].offset,
-					signatures[sig].string,
-					strlen(signatures[sig].string))) {
-			base = bases[current_base].address;
-#if (TDEBUG & TDEBUG_INIT)
-			printk("scsi-t128 : detected board.\n");
-#endif
+int __init t128_detect(Scsi_Host_Template * tpnt)
+{
+	static int current_override = 0, current_base = 0;
+	struct Scsi_Host *instance;
+	unsigned long base;
+	int sig, count;
+
+	tpnt->proc_name = "t128";
+	tpnt->proc_info = &t128_proc_info;
+
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) 
+	{
+		base = 0;
+
+		if (overrides[current_override].address)
+			base = overrides[current_override].address;
+		else
+			for (; !base && (current_base < NO_BASES); ++current_base) {
+				for (sig = 0; sig < NO_SIGNATURES; ++sig)
+					if (!bases[current_base].noauto &&
+					    isa_check_signature(bases[current_base].address + signatures[sig].offset,
+								signatures[sig].string,
+								strlen(signatures[sig].string)))
+					{
+						base = bases[current_base].address;
+						break;
+					}
+			}
+
+		if (!base)
 			break;
-		    }
-	    }
 
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
-	printk("scsi-t128 : base = %08x\n", (unsigned int) base);
-#endif
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL)
+			break;
 
-	if (!base)
-	    break;
+		instance->base = base;
 
-	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	if(instance == NULL)
-		break;
-		
-	instance->base = base;
-
-	NCR5380_init(instance, 0);
-
-	if (overrides[current_override].irq != IRQ_AUTO)
-	    instance->irq = overrides[current_override].irq;
-	else 
-	    instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
-
-	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) {
-		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
-		    instance->host_no, instance->irq);
-		instance->irq = IRQ_NONE;
-	    } 
-
-	if (instance->irq == IRQ_NONE) {
-	    printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
-	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
-	}
+		NCR5380_init(instance, 0);
 
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
-	printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
+
+		if (instance->irq != IRQ_NONE)
+			if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) 
+			{
+				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) {
+			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+		}
+
+		printk(KERN_INFO "scsi%d : at 0x%08lx", instance->host_no,instance->base);
+		if (instance->irq == IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
 
-	printk("scsi%d : at 0x%08lx", instance->host_no, instance->base);
-	if (instance->irq == IRQ_NONE)
-	    printk (" interrupts disabled");
-	else 
-	    printk (" irq %d", instance->irq);
-	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
-	    CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE);
-	NCR5380_print_options(instance);
-	printk("\n");
-
-	++current_override;
-	++count;
-    }
-    return count;
+		++current_override;
+		++count;
+	}
+	return count;
 }
 
-/*
- * Function : int t128_biosparam(Disk * disk, kdev_t dev, int *ip)
+/**
+ *	t128_biosparam		-	disk geometry
+ *	@disk: device 
+ *	@dev: device major/minor
+ *	@ip: array to return results
  *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ *	Generates a BIOS / DOS compatible H-C-S mapping for 
  *	the specified device / size.
  * 
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- *	major / minor, ip[] = {heads, sectors, cylinders}  
- *
- * Returns : always 0 (success), initializes ip
- *	
+ *	Most SCSI boards use this mapping, I could be incorrect.  Some one
+ *	using hard disks on a trantor should verify that this mapping
+ *	corresponds to that used by the BIOS / ASPI driver by running the
+ *	linux fdisk program and matching the H_C_S coordinates to those
+ *	that DOS uses.
  */
 
-/* 
- * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
- */
-
-int t128_biosparam(Disk * disk, kdev_t dev, int * ip)
+int t128_biosparam(Disk * disk, kdev_t dev, int *ip)
 {
-  int size = disk->capacity;
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  return 0;
+	int size = disk->capacity;
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	return 0;
 }
 
-/*
- * Function : int NCR5380_pread (struct Scsi_Host *instance, 
- *	unsigned char *dst, int len)
+/**
+ *	NCR5380_pread		-	pseudo DMA read
+ *	@instance: controller
+ *	@dst: buffer to write to
+ *	@len: expect/max length
  *
- * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 
- *	dst
- * 
- * Inputs : dst = destination, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog 
- * 	timeout.
+ *	Fast 5380 pseudo-dma read function, transfers len bytes to 
+ *	dst from the controller.
  */
 
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
-    int len) {
-    unsigned long reg = instance->base + T_DATA_REG_OFFSET;
-    unsigned char *d = dst;
-    register int i = len;
-
-
-#if 0
-    for (; i; --i) {
-	while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
-#else
-    while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
-    for (; i; --i) {
-#endif
-	*d++ = isa_readb(reg);
-    }
+static inline int NCR5380_pread(struct Scsi_Host *instance,
+				unsigned char *dst, int len)
+{
+	unsigned long reg = instance->base + T_DATA_REG_OFFSET;
+	unsigned char *d = dst;
+	int i = len;
+
+	while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY))
+	       	barrier();
+	for (; i; --i) {
+		*d++ = isa_readb(reg);
+	}
 
-    if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
-	unsigned char tmp;
-	unsigned long foo;
-	foo = instance->base + T_CONTROL_REG_OFFSET;
-	tmp = isa_readb(foo);
-	isa_writeb(tmp | T_CR_CT, foo);
-	isa_writeb(tmp, foo);
-	printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
-	    instance->host_no);
-	return -1;
-    } else
-	return 0;
+	if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
+		unsigned char tmp;
+		unsigned long foo;
+		foo = instance->base + T_CONTROL_REG_OFFSET;
+		tmp = isa_readb(foo);
+		isa_writeb(tmp | T_CR_CT, foo);
+		isa_writeb(tmp, foo);
+		printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pread.\n", instance->host_no);
+		return -1;
+	} else
+		return 0;
 }
 
-/*
- * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
- *	unsigned char *src, int len)
+/**
+ *	NCR5380_pwrite		-	pseudo DMA write
+ *	@instance: controller
+ *	@dst: buffer to write to
+ *	@len: expect/max length
  *
- * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
- *	src
- * 
- * Inputs : src = source, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog 
- * 	timeout.
+ *	Fast 5380 pseudo-dma write function, transfers len bytes from
+ *	dst to the controller.
  */
 
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
-    int len) {
-    unsigned long reg = instance->base + T_DATA_REG_OFFSET;
-    unsigned char *s = src;
-    register int i = len;
-
-#if 0
-    for (; i; --i) {
-	while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
-#else
-    while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
-    for (; i; --i) {
-#endif
-	isa_writeb(*s++, reg);
-    }
 
-    if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
-	unsigned char tmp;
-	unsigned long foo;
-	foo = instance->base + T_CONTROL_REG_OFFSET;
-	tmp = isa_readb(foo);
-	isa_writeb(tmp | T_CR_CT, foo);
-	isa_writeb(tmp, foo);
-	printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
-	    instance->host_no);
-	return -1;
-    } else 
-	return 0;
+static inline int NCR5380_pwrite(struct Scsi_Host *instance,
+				 unsigned char *src, int len)
+{
+	unsigned long reg = instance->base + T_DATA_REG_OFFSET;
+	unsigned char *s = src;
+	int i = len;
+
+	while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY))
+		barrier();
+	for (; i; --i) {
+		isa_writeb(*s++, reg);
+	}
+
+	if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
+		unsigned char tmp;
+		unsigned long foo;
+		foo = instance->base + T_CONTROL_REG_OFFSET;
+		tmp = isa_readb(foo);
+		isa_writeb(tmp | T_CR_CT, foo);
+		isa_writeb(tmp, foo);
+		printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pwrite()\n", instance->host_no);
+		return -1;
+	} else
+		return 0;
 }
 
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- linux-2.4.16/drivers/scsi/tmscsim.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/scsi/tmscsim.c	Tue Dec  4 19:25:31 2001
@@ -1450,7 +1450,7 @@
     int ret_code = -1;
     int size = disk->capacity;
 
-    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
+    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, block_size(devno))))
     {
 	/* try to infer mapping from partition table */
 	ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/Config.in linux/drivers/sound/Config.in
--- linux-2.4.16/drivers/sound/Config.in	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/Config.in	Fri Dec  7 16:54:23 2001
@@ -40,6 +40,9 @@
 dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
 dep_tristate '  ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Intel ICH (i8xx) audio support' CONFIG_SOUND_ICH $CONFIG_PCI
+if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
+    dep_tristate '  IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND
+fi
 dep_tristate '  RME Hammerfall (RME96XX) support' CONFIG_SOUND_RME96XX $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 if [ "$CONFIG_VISWS" = "y" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/Makefile linux/drivers/sound/Makefile
--- linux-2.4.16/drivers/sound/Makefile	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/Makefile	Fri Dec  7 16:54:23 2001
@@ -73,6 +73,7 @@
 obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
 obj-$(CONFIG_SOUND_BT878)	+= btaudio.o
 obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
+obj-$(CONFIG_SOUND_IT8172)     += ite8172.o ac97_codec.o
 
 ifeq ($(CONFIG_MIDI_EMU10K1),y)
   obj-$(CONFIG_SOUND_EMU10K1)	+= sound.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- linux-2.4.16/drivers/sound/ad1848.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/ad1848.c	Wed Dec  5 15:27:58 2001
@@ -30,6 +30,12 @@
  * Aki Laukkanen	: added power management support
  * Arnaldo C. de Melo	: added missing restore_flags in ad1848_resume
  * Miguel Freitas       : added ISA PnP support
+ * Alan Cox		: Added CS4236->4239 identification
+ * Daniel T. Cobra	: Alernate config/mixer for later chips
+ * Alan Cox		: Merged chip idents and config code
+ *
+ * TODO
+ *		APM save restore assist code on IBM thinkpad
  *
  * Status:
  *		Tested. Believed fully functional.
@@ -57,7 +63,7 @@
 	int             dual_dma;	/* 1, when two DMA channels allocated */
 	int 		subtype;
 	unsigned char   MCE_bit;
-	unsigned char   saved_regs[32];
+	unsigned char   saved_regs[64];	/* Includes extended register space */
 	int             debug_flag;
 
 	int             audio_flags;
@@ -78,6 +84,9 @@
 #define MD_IWAVE	7
 #define MD_4235         8 /* Crystal Audio CS4235  */
 #define MD_1845_SSCAPE  9 /* Ensoniq Soundscape PNP*/
+#define MD_4236		10 /* 4236 and higher */
+#define MD_42xB		11 /* CS 42xB */
+#define MD_4239		12 /* CS4239 */
 
 	/* Mixer parameters */
 	int             recmask;
@@ -125,7 +134,7 @@
 
 static int loaded;
 
-static int ad_format_mask[10 /*devc->model */ ] =
+static int ad_format_mask[13 /*devc->model */ ] =
 {
 	0,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
@@ -136,7 +145,10 @@
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE /* CS4235 */,
-	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW	/* Ensoniq Soundscape*/
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW	/* Ensoniq Soundscape*/,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM	
 };
 
 static ad1848_info adev_info[MAX_AUDIO_DEV];
@@ -202,9 +214,22 @@
 
 	save_flags(flags);
 	cli();
-	outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
-	x = inb(io_Indexed_Data(devc));
-/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
+	
+	if(reg < 32)
+	{
+		outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		x = inb(io_Indexed_Data(devc));
+	}
+	else
+	{
+		int xreg, xra;
+
+		xreg = (reg & 0xff) - 32;
+		xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2);
+		outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc));
+		x = inb(io_Indexed_Data(devc));
+	}
 	restore_flags(flags);
 
 	return x;
@@ -220,9 +245,22 @@
 
 	save_flags(flags);
 	cli();
-	outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
-	outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc));
-	/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
+	
+	if(reg < 32)
+	{
+		outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc));
+	}
+	else
+	{
+		int xreg, xra;
+		
+		xreg = (reg & 0xff) - 32;
+		xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2);
+		outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc));
+		outb((unsigned char) (data & 0xff), io_Indexed_Data(devc));
+	}
 	restore_flags(flags);
 }
 
@@ -591,7 +629,13 @@
 			devc->mix_devices = &(iwave_mix_devices[0]);
 			break;
 
+		case MD_42xB:
+		case MD_4239:
+			devc->mix_devices = &(cs42xb_mix_devices[0]);
+			devc->supported_devices = MODE3_MIXER_DEVICES;
+			break;
 		case MD_4232:
+		case MD_4236:
 			devc->supported_devices = MODE3_MIXER_DEVICES;
 			break;
 
@@ -1118,7 +1162,7 @@
 	}
 	old_fs = ad_read(devc, 8);
 
-	if (devc->model == MD_4232)
+	if (devc->model == MD_4232 || devc->model >= MD_4236)
 	{
 		tmp = ad_read(devc, 16);
 		ad_write(devc, 16, tmp | 0x30);
@@ -1139,7 +1183,7 @@
 	while (timeout < 10000 && inb(devc->base) == 0x80)
 		timeout++;
 
-	if (devc->model == MD_4232)
+	if (devc->model >= MD_4232)
 		ad_write(devc, 16, tmp & ~0x30);
 
 	ad_leave_MCE(devc);	/*
@@ -1403,11 +1447,12 @@
 static void ad1848_init_hw(ad1848_info * devc)
 {
 	int i;
+	int *init_values;
 
 	/*
 	 * Initial values for the indirect registers of CS4248/AD1848.
 	 */
-	static int      init_values[] =
+	static int      init_values_a[] =
 	{
 		0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
 		0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
@@ -1417,6 +1462,31 @@
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
 
+	static int      init_values_b[] =
+	{
+		/* 
+		   Values for the newer chips
+		   Some of the register initialization values were changed. In
+		   order to get rid of the click that preceded PCM playback,
+		   calibration was disabled on the 10th byte. On that same byte,
+		   dual DMA was enabled; on the 11th byte, ADC dithering was
+		   enabled, since that is theoretically desirable; on the 13th
+		   byte, Mode 3 was selected, to enable access to extended
+		   registers.
+		 */
+		0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+		0x00, 0x00, 0x06, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 		0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40,
+ 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	/*
+	 *	Select initialisation data
+	 */
+	 
+	init_values = init_values_a;
+	if(devc->model >= MD_4236)
+		init_values = init_values_b;
 
 	for (i = 0; i < 16; i++)
 		ad_write(devc, i, init_values[i]);
@@ -1768,19 +1838,49 @@
 				else
 				{
 					switch (id & 0x1f) {
-					case 3: /* CS4236/CS4235 */
+					case 3: /* CS4236/CS4235/CS42xB/CS4239 */
 						{
 							int xid;
 							ad_write(devc, 12, ad_read(devc, 12) | 0x60); /* switch to mode 3 */
 							ad_write(devc, 23, 0x9c); /* select extended register 25 */
 							xid = inb(io_Indexed_Data(devc));
 							ad_write(devc, 12, ad_read(devc, 12) & ~0x60); /* back to mode 0 */
-							if ((xid & 0x1f) == 0x1d) {
-								devc->chip_name = "CS4235";
-								devc->model = MD_4235;
-							} else {
-								devc->chip_name = "CS4236";
-								devc->model = MD_4232;
+							switch (xid & 0x1f)
+							{
+								case 0x00:
+									devc->chip_name = "CS4237B(B)";
+									devc->model = MD_42xB;
+									break;
+								case 0x08:
+									/* Seems to be a 4238 ?? */
+									devc->chip_name = "CS4238";
+									devc->model = MD_42xB;
+									break;
+								case 0x09:
+									devc->chip_name = "CS4238B";
+									devc->model = MD_42xB;
+									break;
+								case 0x0b:
+									devc->chip_name = "CS4236B";
+									devc->model = MD_4236;
+									break;
+								case 0x10:
+									devc->chip_name = "CS4237B";
+									devc->model = MD_42xB;
+									break;
+								case 0x1d:
+									devc->chip_name = "CS4235";
+									devc->model = MD_4235;
+									break;
+								case 0x1e:
+									devc->chip_name = "CS4239";
+									devc->model = MD_4239;
+									break;
+								default:
+									printk("Chip ident is %X.\n", xid&0x1F);
+									devc->chip_name = "CS42xx";
+									devc->model = MD_4232;
+									break;
 							}
 						}
 						break;
@@ -2747,6 +2847,10 @@
 
 	save_flags(flags);
 	cli();
+	
+	/* Thinkpad is a bit more of PITA than normal. The BIOS tends to
+	   restore it in a different config to the one we use.  Need to
+	   fix this somehow */
 
 	/* store old mixer levels */
 	memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- linux-2.4.16/drivers/sound/ad1848_mixer.h	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/ad1848_mixer.h	Tue Dec  4 19:25:31 2001
@@ -57,14 +57,14 @@
 				 SOUND_MASK_OGAIN)
 
 struct mixer_def {
-	unsigned int regno:5;		/* register number for volume */
+	unsigned int regno:6;		/* register number for volume */
 	unsigned int polarity:1;	/* volume polarity: 0=normal, 1=reversed */
 	unsigned int bitpos:3;		/* position of bits in register for volume */
 	unsigned int nbits:3;		/* number of bits in register for volume */
-	unsigned int mutereg:5;		/* register number for mute bit */
+	unsigned int mutereg:6;		/* register number for mute bit */
 	unsigned int mutepol:1;		/* mute polarity: 0=normal, 1=reversed */
 	unsigned int mutepos:4;		/* position of mute bit in register */
-	unsigned int recreg:5;		/* register number for recording bit */
+	unsigned int recreg:6;		/* register number for recording bit */
 	unsigned int recpol:1;		/* recording polarity: 0=normal, 1=reversed */
 	unsigned int recpos:4;		/* position of recording bit in register */
 };
@@ -104,43 +104,69 @@
 		    rec_reg_r, rec_pola_r, rec_pos_r}}
 
 static mixer_ents ad1848_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	27, 1, 0, 4,	29, 1, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
-MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	13, 1, 2, 6,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
+	MIX_ENT(SOUND_MIXER_VOLUME,	27, 1, 0, 4,	29, 1, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_IMIX,	13, 1, 2, 6,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
 };
 
 static mixer_ents iwave_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	25, 1, 0, 5,	27, 1, 0, 5,  8),
-MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
-MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	16, 1, 0, 5,	17, 1, 0, 5,  8),
-MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
+	MIX_ENT(SOUND_MIXER_VOLUME,	25, 1, 0, 5,	27, 1, 0, 5,  8),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_IMIX,	16, 1, 0, 5,	17, 1, 0, 5,  8),
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
+};
+
+static mixer_ents cs42xb_mix_devices[32] = {
+	/* Digital master volume actually has seven bits, but we only use
+	   six to avoid the discontinuity when the analog gain kicks in. */
+	MIX_ENT(SOUND_MIXER_VOLUME,	46, 1, 0, 6,	47, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	34, 1, 0, 5,	35, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	/* For the IMIX entry, it was not possible to use the MIX_ENT macro
+	   because the mute bit is in different positions for the two
+	   channels and requires reverse polarity. */
+	[SOUND_MIXER_IMIX] = {{13, 1, 2, 6, 13, 1, 0, 0, 0, 8},
+		      {42, 1, 0, 6, 42, 1, 7, 0, 0, 8}},
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	38, 1, 0, 6,	39, 1, 0, 6,  7)
 };
 
 /* OPTi 82C930 has somewhat different port addresses.
@@ -149,68 +175,68 @@
  * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc.
  */
 static mixer_ents c930_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	22, 1, 1, 5,	23, 1, 1, 5,  7),
-MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 5,	 7, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	22, 1, 1, 5,	23, 1, 1, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE,	18, 1, 1, 4,	19, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_MIC,	20, 1, 1, 4,	21, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_CD,		 2, 1, 1, 4,	 3, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 1, 4,	19, 1, 1, 4,  7)
+	MIX_ENT(SOUND_MIXER_VOLUME,	22, 1, 1, 5,	23, 1, 1, 5,  7),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 5,	 7, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	22, 1, 1, 5,	23, 1, 1, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 1, 4,	19, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	20, 1, 1, 4,	21, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 1, 4,	 3, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_IMIX,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 1, 4,	19, 1, 1, 4,  7)
 };
 
 static mixer_ents spro_mix_devices[32] = {
-MIX_ENT (SOUND_MIXER_VOLUME,	19, 0, 4, 4,			 19, 0, 0, 4,  8),
-MIX_ENT (SOUND_MIXER_BASS,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_TREBLE,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT2(SOUND_MIXER_SYNTH,	 4, 1, 1, 4, 23, 0, 3,  0, 0, 8,
-	 			 5, 1, 1, 4, 23, 0, 3, 0, 0, 8),
-MIX_ENT (SOUND_MIXER_PCM,	 6, 1, 1, 4,			  7, 1, 1, 4,  8),
-MIX_ENT (SOUND_MIXER_SPEAKER,	18, 0, 3, 2,			  0, 0, 0, 0,  8),
-MIX_ENT2(SOUND_MIXER_LINE,	20, 0, 4, 4, 17, 1, 4, 16, 0, 2,
-	 			20, 0, 0, 4, 17, 1, 3, 16, 0, 1),
-MIX_ENT2(SOUND_MIXER_MIC,	18, 0, 0, 3, 17, 1, 0, 16, 0, 0,
-	 			 0, 0, 0, 0,  0, 0, 0,  0, 0, 0),
-MIX_ENT2(SOUND_MIXER_CD,	21, 0, 4, 4, 17, 1, 2, 16, 0, 4,
-				21, 0, 0, 4, 17, 1, 1, 16, 0, 3),
-MIX_ENT (SOUND_MIXER_IMIX,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_RECLEV,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_IGAIN,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_OGAIN,	17, 1, 6, 1,			  0, 0, 0, 0,  8),
-/* This is external wavetable */
-MIX_ENT2(SOUND_MIXER_LINE1,	22, 0, 4, 4, 23, 1, 1, 23, 0, 4,
-	 			22, 0, 0, 4, 23, 1, 0, 23, 0, 5),
+	MIX_ENT (SOUND_MIXER_VOLUME,	19, 0, 4, 4,			 19, 0, 0, 4,  8),
+	MIX_ENT (SOUND_MIXER_BASS,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_TREBLE,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT2(SOUND_MIXER_SYNTH,	 4, 1, 1, 4, 23, 0, 3,  0, 0, 8,
+		 			 5, 1, 1, 4, 23, 0, 3, 0, 0, 8),
+	MIX_ENT (SOUND_MIXER_PCM,	 6, 1, 1, 4,			  7, 1, 1, 4,  8),
+	MIX_ENT (SOUND_MIXER_SPEAKER,	18, 0, 3, 2,			  0, 0, 0, 0,  8),
+	MIX_ENT2(SOUND_MIXER_LINE,	20, 0, 4, 4, 17, 1, 4, 16, 0, 2,
+		 			20, 0, 0, 4, 17, 1, 3, 16, 0, 1),
+	MIX_ENT2(SOUND_MIXER_MIC,	18, 0, 0, 3, 17, 1, 0, 16, 0, 0,
+		 			 0, 0, 0, 0,  0, 0, 0,  0, 0, 0),
+	MIX_ENT2(SOUND_MIXER_CD,	21, 0, 4, 4, 17, 1, 2, 16, 0, 4,
+					21, 0, 0, 4, 17, 1, 1, 16, 0, 3),
+	MIX_ENT (SOUND_MIXER_IMIX,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_RECLEV,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_IGAIN,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_OGAIN,	17, 1, 6, 1,			  0, 0, 0, 0,  8),
+	/* This is external wavetable */
+	MIX_ENT2(SOUND_MIXER_LINE1,	22, 0, 4, 4, 23, 1, 1, 23, 0, 4,
+		 			22, 0, 0, 4, 23, 1, 0, 23, 0, 5),
 };
 
 static int default_mixer_levels[32] =
 {
-  0x3232,			/* Master Volume */
-  0x3232,			/* Bass */
-  0x3232,			/* Treble */
-  0x4b4b,			/* FM */
-  0x3232,			/* PCM */
-  0x1515,			/* PC Speaker */
-  0x2020,			/* Ext Line */
-  0x1010,			/* Mic */
-  0x4b4b,			/* CD */
-  0x0000,			/* Recording monitor */
-  0x4b4b,			/* Second PCM */
-  0x4b4b,			/* Recording level */
-  0x4b4b,			/* Input gain */
-  0x4b4b,			/* Output gain */
-  0x2020,			/* Line1 */
-  0x2020,			/* Line2 */
-  0x1515			/* Line3 (usually line in)*/
+	0x3232,			/* Master Volume */
+	0x3232,			/* Bass */
+	0x3232,			/* Treble */
+	0x4b4b,			/* FM */
+	0x3232,			/* PCM */
+	0x1515,			/* PC Speaker */
+	0x2020,			/* Ext Line */
+	0x1010,			/* Mic */
+	0x4b4b,			/* CD */
+	0x0000,			/* Recording monitor */
+	0x4b4b,			/* Second PCM */
+	0x4b4b,			/* Recording level */
+	0x4b4b,			/* Input gain */
+	0x4b4b,			/* Output gain */
+	0x2020,			/* Line1 */
+	0x2020,			/* Line2 */
+	0x1515			/* Line3 (usually line in)*/
 };
 
 #define LEFT_CHN	0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/btaudio.c linux/drivers/sound/btaudio.c
--- linux-2.4.16/drivers/sound/btaudio.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/btaudio.c	Fri Dec  7 18:08:43 2001
@@ -1030,7 +1030,7 @@
         name:     "btaudio",
         id_table: btaudio_pci_tbl,
         probe:    btaudio_probe,
-        remove:   btaudio_remove,
+        remove:   __devexit_p(btaudio_remove),
 };
 
 int btaudio_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- linux-2.4.16/drivers/sound/cs46xx.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/cs46xx.c	Wed Dec  5 17:02:37 2001
@@ -3003,7 +3003,7 @@
 		return -ENODEV;
 
 	case SNDCTL_DSP_SETDUPLEX:
-		return -EINVAL;
+		return 0;
 
 	case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c
--- linux-2.4.16/drivers/sound/emu10k1/main.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/emu10k1/main.c	Fri Dec  7 18:08:43 2001
@@ -1127,7 +1127,7 @@
 	name:		"emu10k1",
 	id_table:	emu10k1_pci_tbl,
 	probe:		emu10k1_probe,
-	remove:		emu10k1_remove,
+	remove:		__devexit_p(emu10k1_remove),
 };
 
 static int __init emu10k1_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.4.16/drivers/sound/i810_audio.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/i810_audio.c	Tue Dec  4 19:25:31 2001
@@ -1405,10 +1405,9 @@
 		if (dmabuf->count < 0) {
 			dmabuf->count = 0;
 		}
-		cnt = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
-		// this is to make the copy_from_user simpler below
-		if(cnt > (dmabuf->dmasize - swptr))
-			cnt = dmabuf->dmasize - swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if(cnt > (dmabuf->dmasize - dmabuf->count))
+			cnt = dmabuf->dmasize - dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 #ifdef DEBUG2
@@ -1419,16 +1418,13 @@
 		if (cnt <= 0) {
 			unsigned long tmo;
 			// There is data waiting to be played
+			i810_update_lvi(state,0);
 			if(!dmabuf->enable && dmabuf->count) {
 				/* force the starting incase SETTRIGGER has been used */
 				/* to stop it, otherwise this is a deadlock situation */
 				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 				start_dac(state);
 			}
-			// Update the LVI pointer in case we have already
-			// written data in this syscall and are just waiting
-			// on the tail bit of data
-			i810_update_lvi(state,0);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				goto ret;
@@ -1860,7 +1856,7 @@
 		if(dmabuf->mapped)
 			abinfo.bytes = dmabuf->count;
 		else
-			abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+			abinfo.bytes = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
 		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 #ifdef DEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- linux-2.4.16/drivers/sound/sb_card.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/sb_card.c	Tue Dec  4 19:25:31 2001
@@ -378,6 +378,11 @@
 		0,0,0,0,
 		0,1,1,-1},
 	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047),
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
 		0,0,0,0,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- linux-2.4.16/drivers/sound/via82cxxx_audio.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Mon Dec 10 18:50:49 2001
@@ -1,6 +1,6 @@
 /*
  * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999,2000 Jeff Garzik
  *
  * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
  * See the "COPYING" file distributed with this software for more info.
@@ -8,9 +8,6 @@
  * 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".
- * If "make pdfdocs" fails, obtain the documentation from
- * the driver's Website at
- * http://gtf.org/garzik/drivers/via82cxxx/
  *
  */
 
@@ -3357,7 +3354,7 @@
 module_init(init_via82cxxx_audio);
 module_exit(cleanup_via82cxxx_audio);
 
-MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("DSP audio and mixer driver for Via 82Cxxx audio devices");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.4.16/drivers/sound/ymfpci.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/sound/ymfpci.c	Sun Dec  9 18:13:45 2001
@@ -39,6 +39,7 @@
  *    native synthesizer through a playback slot.
  *  - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus.
  *  - Make the thing big endian compatible. ALSA has it done.
+ *  - 2001/11/29 ac97_save_state
  */
 
 #include <linux/config.h>
@@ -155,7 +156,7 @@
 			schedule_timeout(1);
 		}
 	} while (end_time - (signed long)jiffies >= 0);
-	printk("ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
+	printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
 	    secondary, ymfpci_readw(codec, reg));
 	return -EBUSY;
 }
@@ -173,19 +174,19 @@
 
 static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
 {
-	ymfpci_t *codec = dev->private_data;
+	ymfpci_t *unit = dev->private_data;
+	int i;
 
-	if (ymfpci_codec_ready(codec, 0, 0))
+	if (ymfpci_codec_ready(unit, 0, 0))
 		return ~0;
-	ymfpci_writew(codec, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
-	if (ymfpci_codec_ready(codec, 0, 0))
+	ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
+	if (ymfpci_codec_ready(unit, 0, 0))
 		return ~0;
-	if (codec->pci->device == PCI_DEVICE_ID_YAMAHA_744 && codec->rev < 2) {
-		int i;
+	if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
 		for (i = 0; i < 600; i++)
-			ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+			ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
 	}
-	return ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+	return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
 }
 
 /*
@@ -404,7 +405,7 @@
 	dmabuf->ready = 1;
 
 #if 0
-	printk("prog_dmabuf: rate %d format 0x%x,"
+	printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
 	    " numfrag %d fragsize %d dmasize %d\n",
 	       state->format.rate, state->format.format, dmabuf->numfrag,
 	       dmabuf->fragsize, dmabuf->dmasize);
@@ -615,7 +616,7 @@
 		dmabuf->hwptr = pos;
 
 		if (dmabuf->count == 0) {
-			printk("ymfpci%d: %d: strain: hwptr %d\n",
+			printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
 			    codec->dev_audio, voice->number, dmabuf->hwptr);
 			ymf_playback_trigger(codec, ypcm, 0);
 		}
@@ -633,7 +634,7 @@
 				/*
 				 * Lost interrupt or other screwage.
 				 */
-				printk("ymfpci%d: %d: lost: delta %d"
+				printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
 				    " hwptr %d swptr %d distance %d count %d\n",
 				    codec->dev_audio, voice->number, delta,
 				    dmabuf->hwptr, swptr, distance, dmabuf->count);
@@ -641,10 +642,10 @@
 				/*
 				 * Normal end of DMA.
 				 */
-//				printk("ymfpci%d: %d: done: delta %d"
-//				    " hwptr %d swptr %d distance %d count %d\n",
-//				    codec->dev_audio, voice->number, delta,
-//				    dmabuf->hwptr, swptr, distance, dmabuf->count);
+				YMFDBGI("ymfpci%d: %d: done: delta %d"
+				    " hwptr %d swptr %d distance %d count %d\n",
+				    codec->dev_audio, voice->number, delta,
+				    dmabuf->hwptr, swptr, distance, dmabuf->count);
 			}
 			played = dmabuf->count;
 			if (ypcm->running) {
@@ -1442,13 +1443,14 @@
 {
 	struct ymf_state *state = (struct ymf_state *)file->private_data;
 	struct ymf_dmabuf *dmabuf;
+	int redzone;
 	unsigned long flags;
 	unsigned int mask = 0;
 
 	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &state->wpcm.dmabuf.wait, wait);
-	// if (file->f_mode & FMODE_READ)
-	// 	poll_wait(file, &dmabuf->wait, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &state->rpcm.dmabuf.wait, wait);
 
 	spin_lock_irqsave(&state->unit->reg_lock, flags);
 	if (file->f_mode & FMODE_READ) {
@@ -1457,12 +1459,21 @@
 			mask |= POLLIN | POLLRDNORM;
 	}
 	if (file->f_mode & FMODE_WRITE) {
+		redzone = ymf_calc_lend(state->format.rate);
+		redzone <<= state->format.shift;
+		redzone *= 3;
+
 		dmabuf = &state->wpcm.dmabuf;
 		if (dmabuf->mapped) {
 			if (dmabuf->count >= (signed)dmabuf->fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		} else {
-			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+			/*
+			 * Don't select unless a full fragment is available.
+			 * Otherwise artsd does GETOSPACE, sees 0, and loops.
+			 */
+			if (dmabuf->count + redzone + dmabuf->fragsize
+			     <= dmabuf->dmasize)
 				mask |= POLLOUT | POLLWRNORM;
 		}
 	}
@@ -1497,6 +1508,7 @@
 		return -EAGAIN;
 	dmabuf->mapped = 1;
 
+/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
 	return 0;
 }
 
@@ -1508,13 +1520,16 @@
 	unsigned long flags;
 	audio_buf_info abinfo;
 	count_info cinfo;
+	int redzone;
 	int val;
 
 	switch (cmd) {
 	case OSS_GETVERSION:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
 		return put_user(SOUND_VERSION, (int *)arg);
 
 	case SNDCTL_DSP_RESET:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
 		if (file->f_mode & FMODE_WRITE) {
 			ymf_wait_dac(state);
 			dmabuf = &state->wpcm.dmabuf;
@@ -1536,6 +1551,7 @@
 		return 0;
 
 	case SNDCTL_DSP_SYNC:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
 		if (file->f_mode & FMODE_WRITE) {
 			dmabuf = &state->wpcm.dmabuf;
 			if (file->f_flags & O_NONBLOCK) {
@@ -1554,6 +1570,7 @@
 	case SNDCTL_DSP_SPEED: /* set smaple rate */
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
 		if (val >= 8000 && val <= 48000) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1585,6 +1602,7 @@
 	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
 		if (file->f_mode & FMODE_WRITE) {
 			ymf_wait_dac(state); 
 			dmabuf = &state->wpcm.dmabuf;
@@ -1606,24 +1624,31 @@
 		return 0;
 
 	case SNDCTL_DSP_GETBLKSIZE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
 		if (file->f_mode & FMODE_WRITE) {
 			if ((val = prog_dmabuf(state, 0)))
 				return val;
-			return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
+			val = state->wpcm.dmabuf.fragsize;
+			YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
+			return put_user(val, (int *)arg);
 		}
 		if (file->f_mode & FMODE_READ) {
 			if ((val = prog_dmabuf(state, 1)))
 				return val;
-			return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
+			val = state->rpcm.dmabuf.fragsize;
+			YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
+			return put_user(val, (int *)arg);
 		}
 		return -EINVAL;
 
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
 		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Select sample format */
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
 		if (val == AFMT_S16_LE || val == AFMT_U8) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1649,6 +1674,7 @@
 	case SNDCTL_DSP_CHANNELS:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
 		if (val != 0) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1676,6 +1702,7 @@
 		return put_user(state->format.voices, (int *)arg);
 
 	case SNDCTL_DSP_POST:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
 		/*
 		 * Quoting OSS PG:
 		 *    The ioctl SNDCTL_DSP_POST is a lightweight version of
@@ -1697,6 +1724,10 @@
 	case SNDCTL_DSP_SETFRAGMENT:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
+		    cmd,
+		    (val >> 16) & 0xFFFF, val & 0xFFFF,
+		    (val >> 16) & 0xFFFF, val & 0xFFFF);
 		dmabuf = &state->wpcm.dmabuf;
 		dmabuf->ossfragshift = val & 0xffff;
 		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
@@ -1707,20 +1738,25 @@
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		dmabuf = &state->wpcm.dmabuf;
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
+		redzone = ymf_calc_lend(state->format.rate);
+		redzone <<= state->format.shift;
+		redzone *= 3;
 		spin_lock_irqsave(&state->unit->reg_lock, flags);
 		abinfo.fragsize = dmabuf->fragsize;
-		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
 		abinfo.fragstotal = dmabuf->numfrag;
 		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_GETISPACE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
 		dmabuf = &state->rpcm.dmabuf;
@@ -1735,15 +1771,18 @@
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_NONBLOCK:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
 		file->f_flags |= O_NONBLOCK;
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
 		/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
 			    (int *)arg); */
 		return put_user(0, (int *)arg);
 
 	case SNDCTL_DSP_GETIPTR:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
 		dmabuf = &state->rpcm.dmabuf;
@@ -1751,13 +1790,13 @@
 		cinfo.bytes = dmabuf->total_bytes;
 		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
 		cinfo.ptr = dmabuf->hwptr;
-		/* XXX fishy - breaks invariant  count=hwptr-swptr */
-		if (dmabuf->mapped)
-			dmabuf->count &= dmabuf->fragsize-1;
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
+		    cinfo.ptr, cinfo.bytes);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_GETOPTR:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		dmabuf = &state->wpcm.dmabuf;
@@ -1765,22 +1804,25 @@
 		cinfo.bytes = dmabuf->total_bytes;
 		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
 		cinfo.ptr = dmabuf->hwptr;
-		/* XXX fishy - breaks invariant  count=swptr-hwptr */
-		if (dmabuf->mapped)
-			dmabuf->count &= dmabuf->fragsize-1;
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
+		    cinfo.ptr, cinfo.bytes);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_SETDUPLEX:	/* XXX TODO */
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
 		return -EINVAL;
 
 	case SOUND_PCM_READ_RATE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
 		return put_user(state->format.rate, (int *)arg);
 
 	case SOUND_PCM_READ_CHANNELS:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
 		return put_user(state->format.voices, (int *)arg);
 
 	case SOUND_PCM_READ_BITS:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
 		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_MAPINBUF:
@@ -1866,13 +1908,12 @@
 	}
 
 #if 0 /* test if interrupts work */
-	ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe);	/* ~ 680ms */
-	ymfpci_writeb(codec, YDSXGR_TIMERCTRL,
+	ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe);	/* ~ 680ms */
+	ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
 	    (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
 #endif
 	up(&unit->open_sem);
 
-	MOD_INC_USE_COUNT;
 	return 0;
 
 out_nodma:
@@ -1896,13 +1937,13 @@
 static int ymf_release(struct inode *inode, struct file *file)
 {
 	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	ymfpci_t *codec = state->unit;
+	ymfpci_t *unit = state->unit;
 
 #if 0 /* test if interrupts work */
-	ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
+	ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
 #endif
 
-	down(&codec->open_sem);
+	down(&unit->open_sem);
 
 	/*
 	 * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
@@ -1919,9 +1960,8 @@
 	file->private_data = NULL;	/* Can you tell I programmed Solaris */
 	kfree(state);
 
-	up(&codec->open_sem);
+	up(&unit->open_sem);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1930,10 +1970,10 @@
  */
 static int ymf_open_mixdev(struct inode *inode, struct file *file)
 {
-	int i;
 	int minor = MINOR(inode->i_rdev);
 	struct list_head *list;
 	ymfpci_t *unit;
+	int i;
 
 	list_for_each(list, &ymf_devs) {
 		unit = list_entry(list, ymfpci_t, ymf_devs);
@@ -1949,7 +1989,6 @@
  match:
 	file->private_data = unit->ac97_codec[i];
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -1963,11 +2002,11 @@
 
 static int ymf_release_mixdev(struct inode *inode, struct file *file)
 {
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static /*const*/ struct file_operations ymf_fops = {
+	owner:		THIS_MODULE,
 	llseek:		no_llseek,
 	read:		ymf_read,
 	write:		ymf_write,
@@ -1979,6 +2018,7 @@
 };
 
 static /*const*/ struct file_operations ymf_mixer_fops = {
+	owner:		THIS_MODULE,
 	llseek:		no_llseek,
 	ioctl:		ymf_ioctl_mixdev,
 	open:		ymf_open_mixdev,
@@ -1990,23 +2030,26 @@
 
 static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
 {
-	int i;
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
 	struct ymf_dmabuf *dmabuf;
 	struct list_head *p;
 	struct ymf_state *state;
 	struct ac97_codec *codec;
+	int i;
 
 	spin_lock_irqsave(&unit->reg_lock, flags);
 
 	unit->suspended = 1;
 
+	/*
+	 * XXX Talk to Kai to remove ac97_save_state before it's too late!
+	 * Other drivers call ac97_reset, which does not have
+	 * a save counterpart. Current ac97_save_state is empty.
+	 */
 	for (i = 0; i < NR_AC97; i++) {
-		codec = unit->ac97_codec[i];
-		if (!codec)
-			continue;
-		ac97_save_state(codec);
+		if ((codec = unit->ac97_codec[i]) != NULL)
+			ac97_save_state(codec);
 	}
 
 	list_for_each(p, &unit->states) {
@@ -2033,23 +2076,16 @@
 
 static int ymf_resume(struct pci_dev *pcidev)
 {
-	int i;
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
 	struct list_head *p;
 	struct ymf_state *state;
 	struct ac97_codec *codec;
+	int i;
 
 	ymfpci_aclink_reset(unit->pci);
 	ymfpci_codec_ready(unit, 0, 1);		/* prints diag if not ready. */
 
-	for (i = 0; i < NR_AC97; i++) {
-		codec = unit->ac97_codec[i];
-		if (!codec)
-			continue;
-		ac97_restore_state(codec);
-	}
-
 #ifdef CONFIG_SOUND_YMFPCI_LEGACY
 	/* XXX At this time the legacy registers are probably deprogrammed. */
 #endif
@@ -2065,6 +2101,11 @@
 		unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
 	}
 
+	for (i = 0; i < NR_AC97; i++) {
+		if ((codec = unit->ac97_codec[i]) != NULL)
+			ac97_restore_state(codec);
+	}
+
 	unit->suspended = 0;
 	list_for_each(p, &unit->states) {
 		state = list_entry(p, struct ymf_state, chain);
@@ -2162,12 +2203,15 @@
 {
 	u8 cmd;
 
+	/*
+	 * In the 744, 754 only 0x01 exists, 0x02 is undefined.
+	 * It does not seem to hurt to trip both regardless of revision.
+	 */
 	pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
-	if (cmd & 0x03) {
-		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
-		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-	}
+	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
+	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+
 	pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
 	pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
 }
@@ -2359,7 +2403,7 @@
 	codec->codec_write = ymfpci_codec_write;
 
 	if (ac97_probe_codec(codec) == 0) {
-		printk("ymfpci: ac97_probe_codec failed\n");
+		printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
 		goto out_kfree;
 	}
 
@@ -2400,6 +2444,7 @@
 static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
 	u16 ctrl;
+	unsigned long base;
 	ymfpci_t *codec;
 
 	int err;
@@ -2408,6 +2453,7 @@
 		printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
 		return err;
 	}
+	base = pci_resource_start(pcidev, 0);
 
 	if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "ymfpci: no core\n");
@@ -2422,16 +2468,21 @@
 	codec->pci = pcidev;
 
 	pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
-	codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);
-	if (codec->reg_area_virt == NULL) {
-		printk(KERN_ERR "ymfpci: unable to map registers\n");
+
+	if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
+		printk(KERN_ERR "ymfpci: unable to request mem region\n");
 		goto out_free;
 	}
 
+	if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
+		printk(KERN_ERR "ymfpci: unable to map registers\n");
+		goto out_release_region;
+	}
+
 	pci_set_master(pcidev);
 
 	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
-	    (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);
+	    (char *)ent->driver_data, base, pcidev->irq);
 
 	ymfpci_aclink_reset(pcidev);
 	if (ymfpci_codec_ready(codec, 0, 1) < 0)
@@ -2461,8 +2512,7 @@
 
 	/* register /dev/dsp */
 	if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
-		printk(KERN_ERR "ymfpci%d: unable to register dsp\n",
-		    codec->dev_audio);
+		printk(KERN_ERR "ymfpci: unable to register dsp\n");
 		goto out_free_irq;
 	}
 
@@ -2508,6 +2558,8 @@
 	ymfpci_writel(codec, YDSXGR_STATUS, ~0);
  out_unmap:
 	iounmap(codec->reg_area_virt);
+ out_release_region:
+	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
  out_free:
 	kfree(codec);
 	return -ENODEV;
@@ -2531,6 +2583,7 @@
 	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
 	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
 	iounmap(codec->reg_area_virt);
+	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
 #ifdef CONFIG_SOUND_YMFPCI_LEGACY
 	if (codec->iomidi) {
 		unload_uart401(&codec->mpu_data);
@@ -2547,7 +2600,7 @@
 	name:		"ymfpci",
 	id_table:	ymf_id_tbl,
 	probe:		ymf_probe_one,
-	remove:         ymf_remove_one,
+	remove:         __devexit_p(ymf_remove_one),
 	suspend:	ymf_suspend,
 	resume:		ymf_resume
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/CDCEther.c linux/drivers/usb/CDCEther.c
--- linux-2.4.16/drivers/usb/CDCEther.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/CDCEther.c	Sun Dec  9 18:02:58 2001
@@ -337,13 +337,9 @@
 	ether_dev_t *ether_dev = (ether_dev_t *)net->priv;
 	int	res;
 
-	// We are finally getting used!
-	MOD_INC_USE_COUNT;
-
 	// Turn on the USB and let the packets flow!!!
 	if ( (res = enable_net_traffic( ether_dev )) ) {
 		err( __FUNCTION__ "can't enable_net_traffic() - %d", res );
-		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -391,9 +387,6 @@
 	usb_unlink_urb( &ether_dev->tx_urb );
 	usb_unlink_urb( &ether_dev->intr_urb );
 	
-	// We are not being used now.
-	MOD_DEC_USE_COUNT;
-
 	// That's it.  I'm done.
 	return 0;
 }
@@ -480,6 +473,7 @@
                      i++, mclist = mclist->next) {
 			memcpy(&mclist->dmi_addr, &buff[i * 6], 6);
 		}
+#if 0
 		usb_control_msg(ether_dev->usb,
 				usb_sndctrlpipe(ether_dev->usb, 0),
 				SET_ETHERNET_MULTICAST_FILTER, /* request */
@@ -489,11 +483,13 @@
 				buff,
 				(6* net->mc_count), /* size */
 				HZ); /* timeout */
+#endif
 		kfree(buff);
 	}
- 
+
+#if 0 
 	CDC_SetEthernetPacketFilter(ether_dev);
-	
+#endif	
         // Tell the kernel to start giving frames to us again.
 	netif_wake_queue(net);
 }
@@ -1210,6 +1206,7 @@
 	// Now that we have an ethernet device, let's set it up
 	// (And I don't mean "set [it] up the bomb".)
 	net->priv = ether_dev;
+	SET_MODULE_OWNER(net);
 	net->open = CDCEther_open;
 	net->stop = CDCEther_close;
 	net->watchdog_timeo = CDC_ETHER_TX_TIMEOUT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/Makefile linux/drivers/usb/Makefile
--- linux-2.4.16/drivers/usb/Makefile	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/Makefile	Tue Dec  4 19:41:21 2001
@@ -79,6 +79,7 @@
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 
 # Object files in subdirectories
+mod-subdirs	:= serial
 
 subdir-$(CONFIG_USB_SERIAL)	+= serial
 subdir-$(CONFIG_USB_STORAGE)	+= storage
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/audio.c linux/drivers/usb/audio.c
--- linux-2.4.16/drivers/usb/audio.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/audio.c	Sun Dec  9 18:02:58 2001
@@ -3362,28 +3362,48 @@
 	struct usb_device *dev = state->s->usbdev;
 	unsigned char data[1];
 #endif
+	unsigned char nr_logical_channels, i;
 
 	usb_audio_recurseunit(state, ftr[4]);
+
+	if (ftr[5] == 0 ) {
+		printk(KERN_ERR "usbaudio: wrong controls size in feature unit %u\n",ftr[3]);
+		return;
+	}
+
 	if (state->nrchannels == 0) {
 		printk(KERN_ERR "usbaudio: feature unit %u source has no channels\n", ftr[3]);
 		return;
 	}
 	if (state->nrchannels > 2)
 		printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
-	if (state->nrchannels == 1 && ftr[0] == 7+ftr[5]) {
-		printk(KERN_DEBUG "usbaudio: workaround for Philips camera microphone descriptor enabled\n");
-		mchftr = ftr[6];
-		chftr = 0;
-	} else {
-		if (ftr[0] < 7+ftr[5]*(1+state->nrchannels)) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", ftr[3]);
-			return;
+
+		nr_logical_channels=(ftr[0]-7)/ftr[5]-1;
+
+		if (nr_logical_channels != state->nrchannels) {
+			printk(KERN_WARNING "usbaudio: warning: found %d of %d logical channels.\n", state->nrchannels,nr_logical_channels);
+
+		if (state->nrchannels == 1 && nr_logical_channels==0) {
+			printk(KERN_INFO "usbaudio: assuming the channel found is the master channel (got a Philips camera?). Should be fine.\n");
+		} else if (state->nrchannels == 1 && nr_logical_channels==2) {
+			printk(KERN_INFO "usbaudio: assuming that a stereo channel connected directly to a mixer is missing in search (got Labtec headset?). Should be fine.\n");
+			state->nrchannels=nr_logical_channels;
+		} else {
+			printk(KERN_WARNING "usbaudio: no idea what's going on..., contact linux-usb-devel@lists.sourceforge.net\n");
 		}
-		mchftr = ftr[6];
+	}
+
+	/* There is always a master channel */
+	mchftr = ftr[6];
+	/* Binary AND over logical channels if they exist */
+	if (nr_logical_channels) {
 		chftr = ftr[6+ftr[5]];
-		if (state->nrchannels > 1)
-			chftr &= ftr[6+2*ftr[5]];
+		for (i = 2; i <= nr_logical_channels; i++)
+			chftr &= ftr[6+i*ftr[5]];
+	} else {
+		chftr = 0;
 	}
+
 	/* volume control */
 	if (chftr & 2) {
 		ch = getmixchannel(state, getvolchannel(state));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c
--- linux-2.4.16/drivers/usb/dabusb.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/dabusb.c	Tue Dec  4 19:25:31 2001
@@ -224,7 +224,7 @@
 			err("kmalloc(sizeof(buff_t))==NULL");
 			goto err;
 		}
-		memset (b, sizeof (buff_t), 0);
+		memset (b, 0, sizeof (buff_t));
 		b->s = s;
 		b->purb = usb_alloc_urb(packets);
 		if (!b->purb) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- linux-2.4.16/drivers/usb/dc2xx.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/dc2xx.c	Tue Dec  4 19:25:31 2001
@@ -112,12 +112,15 @@
 	/* These have a different application level protocol which
 	 * is part of the Flashpoint "DigitaOS".  That supports some
 	 * non-camera devices, and some non-Kodak cameras.
+	 * Use this driver to get USB and "OpenDis" to talk.
 	 */  
 	{ USB_DEVICE(0x040a, 0x0100) },		// Kodak DC-220
 	{ USB_DEVICE(0x040a, 0x0110) },		// Kodak DC-260
 	{ USB_DEVICE(0x040a, 0x0111) },		// Kodak DC-265
 	{ USB_DEVICE(0x040a, 0x0112) },		// Kodak DC-290
 	{ USB_DEVICE(0xf003, 0x6002) },		// HP PhotoSmart C500
+	{ USB_DEVICE(0x03f0, 0x4102) },		// HP PhotoSmart C618
+	{ USB_DEVICE(0x0a17, 0x1001) },		// Pentax EI-200
 
 	/* Other USB devices may well work here too, so long as they
 	 * just stick to half duplex bulk packet exchanges.  That
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/devices.c linux/drivers/usb/devices.c
--- linux-2.4.16/drivers/usb/devices.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/devices.c	Tue Dec  4 19:41:21 2001
@@ -139,9 +139,12 @@
 	{USB_CLASS_PHYSICAL,		"PID"},
 	{USB_CLASS_PRINTER,		"print"},
 	{USB_CLASS_MASS_STORAGE,	"stor."},
-	{USB_CLASS_DATA,		"data"},
+	{USB_CLASS_CDC_DATA,		"data"},
 	{USB_CLASS_APP_SPEC,		"app."},
 	{USB_CLASS_VENDOR_SPEC,		"vend."},
+	{USB_CLASS_STILL_IMAGE,		"still"},
+	{USB_CLASS_CSCID,		"scard"},
+	{USB_CLASS_CONTENT_SEC,		"c-sec"},
 	{-1,				"unk."}		/* leave as last */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/hid-core.c linux/drivers/usb/hid-core.c
--- linux-2.4.16/drivers/usb/hid-core.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/hid-core.c	Tue Dec  4 19:25:31 2001
@@ -1236,7 +1236,7 @@
 
 	c = "Device";
 	for (i = 0; i < hid->maxapplication; i++)
-		if (IS_INPUT_APPLICATION(hid->application[i])) {
+		if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) {
 			c = hid_types[hid->application[i] & 0xffff];
 			break;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- linux-2.4.16/drivers/usb/pegasus.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/pegasus.c	Sun Dec  9 18:02:58 2001
@@ -53,7 +53,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.21 (2001/08/27)"
+#define DRIVER_VERSION "v0.4.22 (2001/12/07)"
 #define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -713,10 +713,8 @@
 	pegasus_t *pegasus = (pegasus_t *)net->priv;
 	int	res;
 
-	MOD_INC_USE_COUNT;
 	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
 		err("can't enable_net_traffic() - %d", res);
-		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
@@ -755,7 +753,6 @@
 #ifdef	PEGASUS_USE_INTR
 	usb_unlink_urb( &pegasus->intr_urb );
 #endif
-	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
@@ -867,6 +864,7 @@
 	
 	pegasus->usb = dev;
 	pegasus->net = net;
+	SET_MODULE_OWNER(net);
 	net->priv = pegasus;
 	net->open = pegasus_open;
 	net->stop = pegasus_close;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/pegasus.h linux/drivers/usb/pegasus.h
--- linux-2.4.16/drivers/usb/pegasus.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/pegasus.h	Sun Dec  9 18:02:58 2001
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
+ *  Copyright (c) 1999,2000 Petko Manolov - Petkan (pmanolov@lnxw.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
@@ -138,6 +138,7 @@
 #define	VENDOR_DLINK		0x2001
 #define	VENDOR_ELSA		0x05cc
 #define	VENDOR_IODATA		0x04bb
+#define	VENDOR_KINGSTON		0x0951
 #define	VENDOR_LANEED		0x056e
 #define	VENDOR_LINKSYS		0x066b
 #define	VENDOR_MELCO		0x0411
@@ -210,6 +211,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
+		DEFAULT_GPIO_RESET)
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/pwc-ctrl.c linux/drivers/usb/pwc-ctrl.c
--- linux-2.4.16/drivers/usb/pwc-ctrl.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/pwc-ctrl.c	Tue Dec  4 19:25:31 2001
@@ -782,7 +782,7 @@
 {
 	char buf;
 
-	if (pdev->type < 675 || pdev->release < 6)
+	if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
 		return 0;	/* Not supported by Nala or Timon < release 6 */
 
 	if (power)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- linux-2.4.16/drivers/usb/pwc-if.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/pwc-if.c	Tue Dec  4 19:25:31 2001
@@ -91,6 +91,8 @@
 	disconnect:		usb_pwc_disconnect,	/* disconnect() */
 };
 
+#define MAX_DEV_HINTS 10
+
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */
@@ -99,13 +101,17 @@
        int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
 static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */
-int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+       int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static struct {
+	int type;
+	char serial_number[30];
+	int device_node;
+	struct pwc_device *pdev;
+} device_hint[MAX_DEV_HINTS];
 
 static struct semaphore mem_lock;
 static void *mem_leak = NULL; /* For delayed kfree()s. See below */
 
-static int video_nr = -1;
-
 /***/
 
 static int  pwc_video_open(struct video_device *vdev, int mode);
@@ -647,7 +653,8 @@
 		errmsg = "Unknown";
 		switch(urb->status) {
 			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
-			case -EPIPE:		errmsg = "Babble/stalled (bad cable?)"; break;
+			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;
+			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;
 			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
 			case -EILSEQ:		errmsg = "CRC/Timeout"; break;
 			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;
@@ -765,6 +772,11 @@
 			} /* .. flen < last_packet_size */
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
+#ifdef 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);
+#endif			
 	}
 	if (awake)
 		wake_up_interruptible(&pdev->frameq);
@@ -1140,7 +1152,7 @@
 	                	return -ERESTARTSYS;
 	                }
 	                schedule();
-	                set_current_state(TASK_INTERRUPTIBLE);
+	               	set_current_state(TASK_INTERRUPTIBLE);
 		}
 		remove_wait_queue(&pdev->frameq, &wait);
 		set_current_state(TASK_RUNNING);
@@ -1595,7 +1607,9 @@
 	struct pwc_device *pdev = NULL;
 	struct video_device *vdev;
 	int vendor_id, product_id, type_id;
-	int i;
+	int i, hint;
+	int video_nr = -1; /* default: use next available device */
+	char serial_number[30];
 
 	free_mem_leak();
 	
@@ -1698,6 +1712,10 @@
 	}
 	else return NULL; /* Not Philips, Askey, Logitech or Samsung, for sure. */
 
+	memset(serial_number, 0, 30);
+	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
+	Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+
 	if (udev->descriptor.bNumConfigurations > 1)
 		Info("Warning: more than 1 configuration available.\n");
 
@@ -1734,6 +1752,21 @@
 	pdev->release = udev->descriptor.bcdDevice;
 	Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
 
+
+	/* Now search device_hint[] table for a match, so we can hint a node number. */
+	for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
+		if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
+		     (device_hint[hint].pdev == NULL)) {
+			/* so far, so good... try serial number */
+			if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
+			    	/* match! */
+			    	video_nr = device_hint[hint].device_node;
+			    	Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+			    	break;
+			}
+		}
+	}
+
 	i = video_register_device(vdev, VFL_TYPE_GRABBER, video_nr);
 	if (i < 0) {
 		Err("Failed to register as video device (%d).\n", i);
@@ -1743,6 +1776,9 @@
 		Trace(TRACE_PROBE, "Registered video struct at 0x%p.\n", vdev);
 		Info("Registered as /dev/video%d.\n", vdev->minor & 0x3F);
 	}
+	/* occupy slot */
+	if (hint < MAX_DEV_HINTS) 
+		device_hint[hint].pdev = pdev;
 
 #if 0
 	/* Shut down camera now (some people like the LED off) */
@@ -1762,6 +1798,7 @@
 static void usb_pwc_disconnect(struct usb_device *udev, void *ptr)
 {
 	struct pwc_device *pdev;
+	int hint;
 
 	lock_kernel();
 	free_mem_leak();
@@ -1815,12 +1852,31 @@
 			pdev->vdev = NULL;
 		}
 	}
+
+	/* search device_hint[] table if we occupy a slot, by any chance */
+	for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+		if (device_hint[hint].pdev == pdev)
+			device_hint[hint].pdev = NULL;
+
 	pdev->udev = NULL;
 	unlock_kernel();
 	kfree(pdev);
 }
 
 
+/* *grunt* We have to do atoi ourselves :-( */
+static int pwc_atoi(char *s)
+{
+	int k = 0;
+	
+	k = 0;
+	while (*s != '\0' && *s >= '0' && *s <= '9') {
+		k = 10 * k + (*s - '0');
+		s++;
+	}
+	return k;
+}
+
 
 /* 
  * Initialization code & module stuff 
@@ -1833,8 +1889,8 @@
 static int trace = -1;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
+static char *dev_hint[10] = { };
 
-MODULE_PARM(video_nr, "i");
 MODULE_PARM(size, "s");
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
 MODULE_PARM(fps, "i");
@@ -1851,13 +1907,16 @@
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
 MODULE_PARM(leds, "2i");
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
+MODULE_PARM(dev_hint, "0-10s");
+MODULE_PARM_DESC(dev_hint, "Device node hints");
+
 MODULE_DESCRIPTION("Philips USB webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
 
 static int __init usb_pwc_init(void)
 {
-	int s;
+	int i, sz;
 	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");
@@ -1874,13 +1933,13 @@
 	
 	if (size) {
 		/* string; try matching with array */
-		for (s = 0; s < PSZ_MAX; s++) {
-			if (!strcmp(sizenames[s], size)) { /* Found! */
-				default_size = s;
+		for (sz = 0; sz < PSZ_MAX; sz++) {
+			if (!strcmp(sizenames[sz], size)) { /* Found! */
+				default_size = sz;
 				break;
 			}
 		}
-		if (s == PSZ_MAX) {
+		if (sz == PSZ_MAX) {
 			Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
 			return -EINVAL;
 		}
@@ -1920,6 +1979,74 @@
 		led_on = leds[0] / 100;
 	if (leds[1] >= 0)
 		led_off = leds[1] / 100;
+
+	/* Big device node whoopla. Basicly, it allows you to assign a 
+	   device node (/dev/videoX) to a camera, based on its type 
+	   & serial number. The format is [type[.serialnumber]:]node.
+
+           Any camera that isn't matched by these rules gets the next 
+           available free device node.
+	 */
+	for (i = 0; i < MAX_DEV_HINTS; i++) {
+		char *s, *colon, *dot;
+
+		/* This loop also initializes the array */
+		device_hint[i].pdev = NULL;
+		s = dev_hint[i];
+		if (s != NULL && *s != '\0') {
+			device_hint[i].type = -1; /* wildcard */
+			strcpy(device_hint[i].serial_number, "*");
+
+			/* parse string: chop at ':' & '/' */
+			colon = dot = s;
+			while (*colon != '\0' && *colon != ':')
+				colon++;
+			while (*dot != '\0' && *dot != '.')
+				dot++;
+			/* Few sanity checks */
+			if (*dot != '\0' && dot > colon) {
+				Err("Malformed camera hint: the colon must be after the dot.\n");
+				return -EINVAL;
+			}
+
+			if (*colon == '\0') {
+				/* No colon */
+				if (*dot != '\0') {
+					Err("Malformed camera hint: no colon + device node given.\n");
+					return -EINVAL;
+				}
+				else {
+					/* No type or serial number specified, just a number. */
+					device_hint[i].device_node = pwc_atoi(s);
+				}
+			}
+			else {
+				/* There's a colon, so we have at least a type and a device node */
+				device_hint[i].type = pwc_atoi(s);
+				device_hint[i].device_node = pwc_atoi(colon + 1);
+				if (*dot != '\0') {
+					/* There's a serial number as well */
+					int k;
+					
+					dot++;
+					k = 0;
+					while (*dot != ':' && k < 29) {
+						device_hint[i].serial_number[k++] = *dot;
+						dot++;
+					}
+					device_hint[i].serial_number[k] = '\0';
+				}
+			}
+#ifdef 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);
+			Debug("  node    : %d\n", device_hint[i].device_node);
+#endif			
+		}
+		else
+			device_hint[i].type = 0; /* not filled */
+	} /* ..for MAX_DEV_HINTS */
 
 	init_MUTEX(&mem_lock);
  	Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/pwc.h linux/drivers/usb/pwc.h
--- linux-2.4.16/drivers/usb/pwc.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/pwc.h	Tue Dec  4 19:25:31 2001
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	3
-#define PWC_VERSION 	"8.3"
+#define PWC_MINOR	4
+#define PWC_VERSION 	"8.4"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- linux-2.4.16/drivers/usb/scanner.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/scanner.c	Tue Dec  4 19:25:31 2001
@@ -278,6 +278,28 @@
  *    - Users are now notified to consult the Documentation/usb/scanner.txt
  *      for common error messages rather than the maintainer.
  *
+ * 0.4.7  11/28/2001
+ *    - Fixed typo in Documentation/scanner.txt.  Thanks to
+ *      Karel <karel.vervaeke@pandora.be> for pointing it out.
+ *    - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de
+ *      Valenzuela" <agaspard@utsi.edu>.
+ *    - Added ID's for Agfa e25.  Thanks to Heinrich 
+ *      Rust <Heinrich.Rust@gmx.de>.  Also reported to work with
+ *      Linux and SANE (?).
+ *    - Added Canon FB620U, D646U, and 1220U ID's.  Thanks to Paul
+ *      Rensing <Paul_Rensing@StanfordAlumni.org>.  For more info
+ *      on Linux support for these models, contact 
+ *      salvestrini@users.sourceforge.net.
+ *    - Added Plustek OpticPro UT12, OpticPro U24, KYE/Genius
+ *      ColorPage-HR6 V2 ID's in addition to many "Unknown" models
+ *      under those vendors.  Thanks to
+ *      Jaeger, Gerhard" <g.jaeger@earthling.net>.  These scanner are
+ *      apparently based upon the LM983x IC's.
+ *    - Applied Frank's patch that addressed some locking and module
+ *      referencing counts.  Thanks to both
+ *      Frank Zago <fzago@greshamstorage.com> and
+ *      Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
+ *
  * TODO
  *    - Performance
  *    - Select/poll methods
@@ -324,17 +346,16 @@
 	struct scn_usb_data *scn;
 	unsigned char *data;
 	scn = urb->context;
-	down(&(scn->sem));
+
 	data = &scn->button;
 	data += 0;		/* Keep gcc from complaining about unused var */
 
 	if (urb->status) {
-		up(&(scn->sem));
 		return;
 	}
 
 	dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
-	up(&(scn->sem));
+
 	return;
 }
 
@@ -358,6 +379,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);
 		return -ENODEV;
 	}
@@ -939,6 +961,7 @@
 /* Check to make sure that the last slot isn't already taken */
 	if (p_scn_table[scn_minor]) {
 		err("probe_scanner: No more minor devices remaining.");
+		up(&scn_mutex);
 		return NULL;
 	}
 
@@ -946,6 +969,7 @@
 
 	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
 		err("probe_scanner: Out of memory.");
+		up(&scn_mutex);
 		return NULL;
 	}
 	memset (scn, 0, sizeof(struct scn_usb_data));
@@ -1028,9 +1052,11 @@
 	if (scn->devfs == NULL)
 		dbg("scanner%d: device node registration failed", scn_minor);
 
+	p_scn_table[scn_minor] = scn;
+
 	up(&scn_mutex);
 
-	return p_scn_table[scn_minor] = scn;
+	return scn;
 }
 
 static void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- linux-2.4.16/drivers/usb/scanner.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/scanner.h	Tue Dec  4 19:25:31 2001
@@ -86,12 +86,23 @@
 	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
 	{ USB_DEVICE(0x06bd, 0x0100) },	/* SnapScan Touch */
 	{ USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
+	{ USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
 	{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
 	{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
+	/* Canon */
+	{ USB_DEVICE(0x04a9, 0x2202) }, /* FB620U */
+	{ USB_DEVICE(0x04a9, 0x220b) }, /* D646U */
+	{ USB_DEVICE(0x04a9, 0x2207) }, /* 1220U */
 	/* Colorado -- See Primax/Colorado below */
 	/* Epson -- See Seiko/Epson below */
 	/* Genius */
 	{ 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  */
 	/* Hewlett Packard */
 	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
 	{ USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
@@ -108,6 +119,8 @@
 	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
 	/* Lifetec */
 	{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
+	/* Memorex */
+	{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
 	/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
 	//	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
 	//	{ USB_DEVICE(0x05da, 0x0094) },	/* Phantom 336CX - C3 */
@@ -128,6 +141,19 @@
 	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
 	{ USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
 	{ USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+	/* 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, 0x0012) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0015) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
 	/* Primax/Colorado */
 	{ USB_DEVICE(0x0461, 0x0300) },	/* G2-300 #1 */
 	{ USB_DEVICE(0x0461, 0x0380) },	/* G2-600 #1 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- linux-2.4.16/drivers/usb/serial/belkin_sa.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Tue Dec  4 19:25:31 2001
@@ -140,7 +140,7 @@
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 /* All of the device info needed for the Belkin dockstation serial converter */
-struct usb_serial_device_type belkin_dockstation_device = {
+static struct usb_serial_device_type belkin_dockstation_device = {
 	name:			"Belkin F5U120-PC USB Serial Adapter",
 	id_table:		belkin_dockstation_table,		/* the Belkin F5U103 device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -161,7 +161,7 @@
 };
 
 /* All of the device info needed for the Belkin serial converter */
-struct usb_serial_device_type belkin_sa_device = {
+static struct usb_serial_device_type belkin_sa_device = {
 	name:			"Belkin F5U103 USB Serial Adapter",
 	id_table:		belkin_sa_table,		/* the Belkin F5U103 device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -183,7 +183,7 @@
 
 
 /* This driver also supports the "old" school Belkin single port adaptor */
-struct usb_serial_device_type belkin_old_device = {
+static struct usb_serial_device_type belkin_old_device = {
 	name:			"Belkin USB Serial Adapter",
 	id_table:		belkin_old_table,		/* the old Belkin device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -204,7 +204,7 @@
 };
 
 /* this driver also works for the Peracom single port adapter */
-struct usb_serial_device_type peracom_device = {
+static struct usb_serial_device_type peracom_device = {
 	name:			"Peracom single port USB Serial Adapter",
 	id_table:		peracom_table,			/* the Peracom device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -225,7 +225,7 @@
 };
 
 /* the GoHubs Go-COM232 device is the same as the Peracom single port adapter */
-struct usb_serial_device_type gocom232_device = {
+static struct usb_serial_device_type gocom232_device = {
 	name:			"GO-COM232 USB Serial Converter",
 	id_table:		gocom232_table,			/* the GO-COM232 device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/cyberjack.c linux/drivers/usb/serial/cyberjack.c
--- linux-2.4.16/drivers/usb/serial/cyberjack.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/cyberjack.c	Tue Dec  4 19:25:31 2001
@@ -76,7 +76,7 @@
 
 MODULE_DEVICE_TABLE (usb, id_table);
 
-struct usb_serial_device_type cyberjack_device = {
+static struct usb_serial_device_type cyberjack_device = {
 	name:			"Reiner SCT Cyberjack USB card reader",
 	id_table:		id_table,
 	needs_interrupt_in:	MUST_HAVE,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- linux-2.4.16/drivers/usb/serial/empeg.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/empeg.c	Tue Dec  4 19:25:31 2001
@@ -113,7 +113,7 @@
 
 MODULE_DEVICE_TABLE (usb, id_table);
 
-struct usb_serial_device_type empeg_device = {
+static struct usb_serial_device_type empeg_device = {
 	name:			"Empeg",
 	id_table:		id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,	/* must not have an interrupt in endpoint */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.16/drivers/usb/serial/ftdi_sio.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Tue Dec  4 19:25:31 2001
@@ -173,7 +173,7 @@
 /* Should rename most ftdi_sio's to ftdi_ now since there are two devices 
    which share common code */ 
 
-struct usb_serial_device_type ftdi_sio_device = {
+static struct usb_serial_device_type ftdi_sio_device = {
 	name:			"FTDI SIO",
 	id_table:		id_table_sio,
 	needs_interrupt_in:	MUST_HAVE_NOT,
@@ -196,7 +196,7 @@
         shutdown:               ftdi_sio_shutdown,
 };
 
-struct usb_serial_device_type ftdi_8U232AM_device = {
+static struct usb_serial_device_type ftdi_8U232AM_device = {
 	name:			"FTDI 8U232AM",
 	id_table:		id_table_8U232AM,
 	needs_interrupt_in:	DONT_CARE,
@@ -660,7 +660,7 @@
 } /* ftdi_sio_serial_read_bulk_callback */
 
 
-__u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
+static __u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
 { /* translate_baudrate_to_ftdi */
 	
 	__u16 urb_value = ftdi_sio_b9600;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- linux-2.4.16/drivers/usb/serial/io_edgeport.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Tue Dec  4 19:25:31 2001
@@ -318,11 +318,6 @@
 };
 
 
-/* the info for all of the devices that this driver supports */
-int EdgeportDevices[] = EDGEPORT_DEVICE_IDS;
-#define NUM_EDGEPORT_DEVICES (sizeof(EdgeportDevices) / sizeof(int))
-
-
 /* Transmit Fifo 
  * This Transmit queue is an extension of the edgeport Rx buffer. 
  * The maximum amount of data buffered in both the edgeport 
@@ -495,17 +490,15 @@
 // ************************************************************************
 // ************************************************************************
 
-// These functions should be in firmware.c
-
 /************************************************************************
  *									*
- *	update_edgeport_E2PROM()	Compare current versions of		*
+ * update_edgeport_E2PROM()	Compare current versions of		*
  *				Boot ROM and Manufacture 		*
  *				Descriptors with versions		*
  *				embedded in this driver			*
  *									*
  ************************************************************************/
-void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
+static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
 {
 	__u32 BootCurVer;
 	__u32 BootNewVer;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- linux-2.4.16/drivers/usb/serial/keyspan.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/keyspan.c	Tue Dec  4 19:25:31 2001
@@ -176,7 +176,7 @@
 
 
 /* Functions used by new usb-serial code. */
-int keyspan_init (void)
+static int __init keyspan_init (void)
 {
 	usb_serial_register (&keyspan_usa18x_pre_device);
 	usb_serial_register (&keyspan_usa19_pre_device);
@@ -201,7 +201,7 @@
 	return 0;
 }
 
-void keyspan_exit (void)
+static void __exit keyspan_exit (void)
 {
 	usb_serial_deregister (&keyspan_usa18x_pre_device);
 	usb_serial_deregister (&keyspan_usa19_pre_device);
@@ -1089,7 +1089,7 @@
 	return urb;
 }
 
-struct callbacks {
+static struct callbacks {
 	void	(*instat_callback)(urb_t *);
 	void	(*glocont_callback)(urb_t *);
 	void	(*indat_callback)(urb_t *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h
--- linux-2.4.16/drivers/usb/serial/keyspan.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/keyspan.h	Tue Dec  4 19:25:31 2001
@@ -448,7 +448,7 @@
 };
 
     /* Structs for the devices, pre and post renumeration. */
-struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_usa18x_pre_device = {
 	name:			"Keyspan USA18X - (without firmware)",
 	id_table:		keyspan_usa18x_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -461,7 +461,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa19_pre_device = {
+static struct usb_serial_device_type keyspan_usa19_pre_device = {
 	name:			"Keyspan USA19 - (without firmware)",
 	id_table:		keyspan_usa19_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -475,7 +475,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa19w_pre_device = {
+static struct usb_serial_device_type keyspan_usa19w_pre_device = {
 	name:			"Keyspan USA19W - (without firmware)",
 	id_table:		keyspan_usa19w_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -489,7 +489,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa28_pre_device = {
+static struct usb_serial_device_type keyspan_usa28_pre_device = {
 	name:			"Keyspan USA28 - (without firmware)",
 	id_table:		keyspan_usa28_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -502,7 +502,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa28x_pre_device = {
+static struct usb_serial_device_type keyspan_usa28x_pre_device = {
 	name:			"Keyspan USA28X - (without firmware)",
 	id_table:		keyspan_usa28x_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -515,7 +515,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa28xa_pre_device = {
+static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
 	name:			"Keyspan USA28XA - (without firmware)",
 	id_table:		keyspan_usa28xa_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -528,7 +528,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa28xb_pre_device = {
+static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
 	name:			"Keyspan USA28XB - (without firmware)",
 	id_table:		keyspan_usa28xb_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -541,7 +541,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa49w_pre_device = {
+static struct usb_serial_device_type keyspan_usa49w_pre_device = {
 	name:			"Keyspan USA49W - (without firmware)",
 	id_table:		keyspan_usa49w_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -554,7 +554,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa18x_device = {
+static struct usb_serial_device_type keyspan_usa18x_device = {
 	name:			"Keyspan USA18X",
 	id_table:		keyspan_usa18x_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -580,7 +580,7 @@
 	shutdown:		keyspan_shutdown,
 };
 
-struct usb_serial_device_type keyspan_usa19_device = {
+static struct usb_serial_device_type keyspan_usa19_device = {
 	name:			"Keyspan USA19",
 	id_table:		keyspan_usa19_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -607,7 +607,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa19w_device = {
+static struct usb_serial_device_type keyspan_usa19w_device = {
 	name:			"Keyspan USA19W",
 	id_table:		keyspan_usa19w_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -634,7 +634,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa28_device = {
+static struct usb_serial_device_type keyspan_usa28_device = {
 	name:			"Keyspan USA28",
 	id_table:		keyspan_usa28_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -652,7 +652,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa28x_device = {
+static struct usb_serial_device_type keyspan_usa28x_device = {
 	name:			"Keyspan USA28X/XB",
 	id_table:		keyspan_usa28x_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -679,7 +679,7 @@
 
 };
 
-struct usb_serial_device_type keyspan_usa28xa_device = {
+static struct usb_serial_device_type keyspan_usa28xa_device = {
 	name:			"Keyspan USA28XA",
 	id_table:		keyspan_usa28xa_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -706,7 +706,7 @@
 
 };
 
-struct usb_serial_device_type keyspan_usa49w_device = {
+static struct usb_serial_device_type keyspan_usa49w_device = {
 	name:			"Keyspan USA49W",
 	id_table:		keyspan_usa49w_ids,
 	needs_interrupt_in:	DONT_CARE,	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- linux-2.4.16/drivers/usb/serial/mct_u232.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/mct_u232.c	Sun Dec  9 18:02:58 2001
@@ -27,6 +27,9 @@
  * 10-Nov-2001 Wolfgang Grandegger
  *   - Fixed an endianess problem with the baudrate selection for PowerPC.
  *
+ * 06-Dec-2001 Martin Hamilton <martinh@gnu.org>
+ *	Added support for the Belkin F5U109 DB9 adaptor
+ *
  * 30-May-2001 Greg Kroah-Hartman
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -133,11 +136,13 @@
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
+	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
 	{ }		/* Terminating entry */
 };
 
 static __devinitdata struct usb_device_id mct_u232_table [] = {
         { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
+	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
         { }                        /* Terminating entry */
 };
 
@@ -154,7 +159,7 @@
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 
-struct usb_serial_device_type mct_u232_device = {
+static struct usb_serial_device_type mct_u232_device = {
 	name:		     "Magic Control Technology USB-RS232",
 	id_table:	     mct_u232_table,
 	needs_interrupt_in:  MUST_HAVE,	 /* 2 interrupt-in endpoints */
@@ -178,7 +183,7 @@
 	shutdown:	     mct_u232_shutdown,
 };
 
-struct usb_serial_device_type mct_u232_sitecom_device = {
+static struct usb_serial_device_type mct_u232_sitecom_device = {
 	name:		     "MCT/Sitecom USB-RS232",
 	id_table:	     mct_u232_sitecom_table,
 	needs_interrupt_in:  MUST_HAVE,	 /* 2 interrupt-in endpoints */
@@ -202,7 +207,7 @@
 	shutdown:	     mct_u232_shutdown,
 };
 
-struct usb_serial_device_type mct_u232_du_h3sp_device = {
+static struct usb_serial_device_type mct_u232_du_h3sp_device = {
         name:                "MCT/D-Link DU-H3SP USB BAY",
         id_table:            mct_u232_du_h3sp_table,
         needs_interrupt_in:  MUST_HAVE,  /* 2 interrupt-in endpoints */
@@ -243,7 +248,8 @@
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
 static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) {
-	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID) {
+	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID
+	  || serial->dev->descriptor.idProduct == MCT_U232_BELKIN_F5U109_PID) {
 		switch (value) {
 			case    300: return 0x01;
 			case    600: return 0x02; /* this one not tested */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/mct_u232.h linux/drivers/usb/serial/mct_u232.h
--- linux-2.4.16/drivers/usb/serial/mct_u232.h	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/mct_u232.h	Sun Dec  9 18:02:58 2001
@@ -30,9 +30,12 @@
 #define MCT_U232_SITECOM_PID		0x0230	/* Sitecom Product Id */
 
 /* DU-H3SP USB BAY hub */
-
 #define MCT_U232_DU_H3SP_PID		0x0200	/* D-Link DU-H3SP USB BAY */
 
+/* Belkin badge the MCT U232-P9 as the F5U109 */
+#define MCT_U232_BELKIN_F5U109_VID	0x050d	/* Vendor Id */
+#define MCT_U232_BELKIN_F5U109_PID	0x0109	/* Product Id */
+
 /*
  * Vendor Request Interface
  */
@@ -363,6 +366,25 @@
  * 	  bmAttributes        =   03 (Interrupt)
  * 	  wMaxPacketSize      = 0002
  * 	  bInterval           =   02
+ *
+ *
+ * Hardware details (added by Martin Hamilton, 2001/12/06)
+ * -----------------------------------------------------------------
+ *
+ * This info was gleaned from opening a Belkin F5U109 DB9 USB serial
+ * adaptor, which turns out to simply be a re-badged U232-P9.  We
+ * know this because there is a sticky label on the circuit board
+ * which says "U232-P9" ;-)
+ * 
+ * The circuit board inside the adaptor contains a Philips PDIUSBD12
+ * USB endpoint chip and a Phillips P87C52UBAA microcontroller with
+ * embedded UART.  Exhaustive documentation for these is available at:
+ *
+ *   http://www.semiconductors.philips.com/pip/p87c52ubaa
+ *   http://www.semiconductors.philips.com/pip/pdiusbd12
+ *
+ * Thanks to Julian Highfield for the pointer to the Philips database.
+ * 
  */
 
 #endif /* __LINUX_USB_SERIAL_MCT_U232_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- linux-2.4.16/drivers/usb/serial/omninet.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/omninet.c	Tue Dec  4 19:25:31 2001
@@ -87,7 +87,7 @@
 MODULE_DEVICE_TABLE (usb, id_table);
 
 
-struct usb_serial_device_type zyxel_omninet_device = {
+static struct usb_serial_device_type zyxel_omninet_device = {
 	name:			"ZyXEL - omni.net lcd plus usb",
 	id_table:		id_table,
 	needs_interrupt_in:	MUST_HAVE,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- linux-2.4.16/drivers/usb/serial/usbserial.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/usbserial.c	Tue Dec  4 19:25:31 2001
@@ -397,7 +397,7 @@
 static struct usb_serial	*serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
 
 
-LIST_HEAD(usb_serial_driver_list);
+static LIST_HEAD(usb_serial_driver_list);
 
 
 static struct usb_serial *get_serial_by_minor (int minor)
@@ -1433,7 +1433,7 @@
 };
 
 
-int usb_serial_init(void)
+static int __init usb_serial_init(void)
 {
 	int i;
 	int result;
@@ -1473,7 +1473,7 @@
 }
 
 
-void usb_serial_exit(void)
+static void __exit usb_serial_exit(void)
 {
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- linux-2.4.16/drivers/usb/serial/visor.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/visor.c	Tue Dec  4 19:41:21 2001
@@ -184,7 +184,7 @@
 
 
 /* All of the device info needed for the Handspring Visor */
-struct usb_serial_device_type handspring_device = {
+static struct usb_serial_device_type handspring_device = {
 	name:			"Handspring Visor",
 	id_table:		visor_id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
@@ -210,7 +210,7 @@
 };
 
 /* device info for the Palm 4.0 devices */
-struct usb_serial_device_type palm_4_0_device = {
+static struct usb_serial_device_type palm_4_0_device = {
 	name:			"Palm 4.0",
 	id_table:		palm_4_0_id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
@@ -714,9 +714,8 @@
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			visor_close (&serial->port[i], NULL);
-		}
+		serial->port[i].active = 0;
+		serial->port[i].open_count = 0;
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- linux-2.4.16/drivers/usb/serial/whiteheat.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/serial/whiteheat.c	Tue Dec  4 19:25:31 2001
@@ -131,7 +131,7 @@
 static int  whiteheat_startup		(struct usb_serial *serial);
 static void whiteheat_shutdown		(struct usb_serial *serial);
 
-struct usb_serial_device_type whiteheat_fake_device = {
+static struct usb_serial_device_type whiteheat_fake_device = {
 	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",
 	id_table:		id_table_prerenumeration,
 	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
@@ -144,7 +144,7 @@
 	startup:		whiteheat_startup	
 };
 
-struct usb_serial_device_type whiteheat_device = {
+static struct usb_serial_device_type whiteheat_device = {
 	name:			"Connect Tech - WhiteHEAT",
 	id_table:		id_table_std,
 	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- linux-2.4.16/drivers/usb/uhci.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/uhci.c	Fri Dec  7 18:08:43 2001
@@ -2990,7 +2990,7 @@
 	id_table:	uhci_pci_ids,
 
 	probe:		uhci_pci_probe,
-	remove:		uhci_pci_remove,
+	remove:		__devexit_p(uhci_pci_remove),
 
 #ifdef	CONFIG_PM
 	suspend:	uhci_pci_suspend,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- linux-2.4.16/drivers/usb/usb-ohci.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/usb-ohci.c	Fri Dec  7 18:08:43 2001
@@ -2860,7 +2860,7 @@
 	id_table:	&ohci_pci_ids [0],
 
 	probe:		ohci_pci_probe,
-	remove:		ohci_pci_remove,
+	remove:		__devexit_p(ohci_pci_remove),
 
 #ifdef	CONFIG_PM
 	suspend:	ohci_pci_suspend,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- linux-2.4.16/drivers/usb/usb-uhci.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/usb-uhci.c	Fri Dec  7 18:08:43 2001
@@ -3070,7 +3070,7 @@
 	id_table:	&uhci_pci_ids [0],
 
 	probe:		uhci_pci_probe,
-	remove:		uhci_pci_remove,
+	remove:		__devexit_p(uhci_pci_remove),
 
 #ifdef	CONFIG_PM
 	suspend:	uhci_pci_suspend,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/usb/usbnet.c linux/drivers/usb/usbnet.c
--- linux-2.4.16/drivers/usb/usbnet.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/usb/usbnet.c	Tue Dec  4 19:25:31 2001
@@ -1870,6 +1870,11 @@
 	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
 	driver_info:	(unsigned long) &an2720_info,
 },
+
+{
+	USB_DEVICE (0x0547, 0x2727),	// Xircom PGUNET
+	driver_info:	(unsigned long) &an2720_info,
+},
 #endif
 
 #ifdef	CONFIG_USB_BELKIN
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- linux-2.4.16/drivers/video/aty/atyfb_base.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/aty/atyfb_base.c	Thu Dec  6 15:41:46 2001
@@ -88,6 +88,9 @@
 #include <linux/adb.h>
 #include <linux/pmu.h>
 #endif
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif
 #ifdef CONFIG_NVRAM
 #include <linux/nvram.h>
 #endif
@@ -251,11 +254,11 @@
 static int default_mclk __initdata = 0;
 
 #ifndef MODULE
-static const char *mode_option __initdata = NULL;
+static char *mode_option __initdata = NULL;
 #endif
 
 #ifdef CONFIG_PPC
-#ifdef CONFIG_NVRAM_NOT_DEFINED
+#ifndef CONFIG_NVRAM
 static int default_vmode __initdata = VMODE_NVRAM;
 static int default_cmode __initdata = CMODE_NVRAM;
 #else
@@ -271,31 +274,35 @@
 static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
 #endif
 
-static const char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
-static const char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
-static const char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
-static const char m64n_et[] __initdata = "mach64ET (ATI264ET)";
-static const char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
-static const char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
-static const char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
-static const char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
-static const char m64n_gt[] __initdata = "3D RAGE (GT)";
-static const char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
-static const char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
-static const char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
-static const char m64n_lt[] __initdata = "3D RAGE LT";
-static const char m64n_ltg[] __initdata = "3D RAGE LT-G";
-static const char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
-static const char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
-static const char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
-static const char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
-static const char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
-static const char m64n_xl[] __initdata = "3D RAGE (XL)";
-static const char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
-static const char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
-static const char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
-static const char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
+#ifdef CONFIG_FB_ATY_GX
+static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
+static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
+#endif /* CONFIG_FB_ATY_GX */
 
+#ifdef CONFIG_FB_ATY_CT
+static char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
+static char m64n_et[] __initdata = "mach64ET (ATI264ET)";
+static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
+static char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
+static char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
+static char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
+static char m64n_gt[] __initdata = "3D RAGE (GT)";
+static char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
+static char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
+static char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
+static char m64n_lt[] __initdata = "3D RAGE LT";
+static char m64n_ltg[] __initdata = "3D RAGE LT-G";
+static char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
+static char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
+static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
+static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
+static char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
+static char m64n_xl[] __initdata = "3D RAGE (XL)";
+static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
+static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
+static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
+static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
+#endif /* CONFIG_FB_ATY_CT */
 
 static const struct {
     u16 pci_id, chip_type;
@@ -357,24 +364,32 @@
 #endif /* CONFIG_FB_ATY_CT */
 };
 
-static const char ram_dram[] __initdata = "DRAM";
-static const char ram_vram[] __initdata = "VRAM";
-static const char ram_edo[] __initdata = "EDO";
-static const char ram_sdram[] __initdata = "SDRAM";
-static const char ram_sgram[] __initdata = "SGRAM";
-static const char ram_wram[] __initdata = "WRAM";
-static const char ram_off[] __initdata = "OFF";
-static const char ram_resv[] __initdata = "RESV";
+#if defined(CONFIG_FB_ATY_GX) || defined(CONFIG_FB_ATY_CT)
+static char ram_dram[] __initdata = "DRAM";
+#endif /* CONFIG_FB_ATY_GX || CONFIG_FB_ATY_CT */
+
+#ifdef CONFIG_FB_ATY_GX
+static char ram_vram[] __initdata = "VRAM";
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+static char ram_edo[] __initdata = "EDO";
+static char ram_sdram[] __initdata = "SDRAM";
+static char ram_sgram[] __initdata = "SGRAM";
+static char ram_wram[] __initdata = "WRAM";
+static char ram_off[] __initdata = "OFF";
+static char ram_resv[] __initdata = "RESV";
+#endif /* CONFIG_FB_ATY_CT */
 
 #ifdef CONFIG_FB_ATY_GX
-static const char *aty_gx_ram[8] __initdata = {
+static char *aty_gx_ram[8] __initdata = {
     ram_dram, ram_vram, ram_vram, ram_dram,
     ram_dram, ram_vram, ram_vram, ram_resv
 };
 #endif /* CONFIG_FB_ATY_GX */
 
 #ifdef CONFIG_FB_ATY_CT
-static const char *aty_ct_ram[8] __initdata = {
+static char *aty_ct_ram[8] __initdata = {
     ram_off, ram_dram, ram_edo, ram_edo,
     ram_sdram, ram_sgram, ram_wram, ram_resv
 };
@@ -819,6 +834,13 @@
 	display_info.disp_reg_address = info->ati_regbase_phys;
     }
 #endif /* CONFIG_FB_COMPAT_XPMAC */
+#ifdef CONFIG_BOOTX_TEXT
+    btext_update_display(info->frame_buffer_phys,
+			 (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8,
+			 ((par->crtc.v_tot_disp>>16) & 0x7ff)+1,
+			 par->crtc.bpp,
+			 par->crtc.vxres*par->crtc.bpp/8);
+#endif /* CONFIG_BOOTX_TEXT */
 }
 
 static int atyfb_decode_var(const struct fb_var_screeninfo *var,
@@ -1638,6 +1660,8 @@
 			}
 			break;
 		case PBOOK_SLEEP_NOW:
+			if (currcon >= 0)
+				fb_display[currcon].dispsw = &fbcon_dummy;
 			if (info->blitter_may_be_busy)
 				wait_for_idle(info);
 			/* Stop accel engine (stop bus mastering) */
@@ -1667,7 +1691,11 @@
 				info->save_framebuffer = 0;
 			}
 			/* Restore display */
-			atyfb_set_par(&info->current_par, info);
+			if (currcon >= 0) {
+				atyfb_set_dispsw(&fb_display[currcon],
+					info, info->current_par.crtc.bpp,
+					info->current_par.accel_flags & FB_ACCELF_TEXT);
+			}
 			atyfbcon_blank(0, (struct fb_info *)info);
 			break;
 		}
@@ -2020,13 +2048,6 @@
 		if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
 		    var = default_var;
 	    } else {
-#ifdef CONFIG_NVRAM
-		if (default_vmode == VMODE_NVRAM) {
-		    default_vmode = nvram_read_byte(NV_VMODE);
-		    if (default_vmode <= 0 || default_vmode > VMODE_MAX)
-			default_vmode = VMODE_CHOOSE;
-		}
-#endif
 		if (default_vmode == VMODE_CHOOSE) {
 		    if (M64_HAS(G3_PB_1024x768))
 			/* G3 PowerBook with 1024x768 LCD */
@@ -2139,11 +2160,16 @@
 	return -ENXIO;
 #else
     u16 tmp;
+    int aux_app;
+    unsigned long raddr;
 #endif
 
     while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
 	if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
 	    struct resource *rp;
+#ifndef __sparc__
+	    struct resource *rrp;
+#endif
 
 	    for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--)
 		if (pdev->device == aty_chips[i].pci_id)
@@ -2375,9 +2401,19 @@
 	    }
 #else /* __sparc__ */
 
-	    info->ati_regbase_phys = 0x7ff000 + addr;
-	    info->ati_regbase = (unsigned long)
-				ioremap(info->ati_regbase_phys, 0x1000);
+	    aux_app = 0;
+	    raddr = addr + 0x7ff000UL;
+	    rrp = &pdev->resource[2];
+	    if ((rrp->flags & IORESOURCE_MEM)
+		&& request_mem_region(rrp->start, rrp->end - rrp->start + 1,
+				      "atyfb")) {
+		    aux_app = 1;
+		    raddr = rrp->start;
+		    printk(KERN_INFO "atyfb: using auxiliary register aperture\n");
+	    }
+
+	    info->ati_regbase_phys = raddr;
+	    info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000);
 
 	    if(!info->ati_regbase) {
 		    kfree(info);
@@ -2385,8 +2421,8 @@
 		    return -ENOMEM;
 	    }
 
-	    info->ati_regbase_phys += 0xc00;
-	    info->ati_regbase += 0xc00;
+	    info->ati_regbase_phys += aux_app? 0x400: 0xc00;
+	    info->ati_regbase += aux_app? 0x400: 0xc00;
 
 	    /*
 	     * Enable memory-space accesses using config-space
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- linux-2.4.16/drivers/video/cyber2000fb.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/cyber2000fb.c	Fri Dec  7 18:08:43 2001
@@ -1683,7 +1683,7 @@
 static struct pci_driver cyberpro_driver = {
 	name:		"CyberPro",
 	probe:		cyberpro_probe,
-	remove:		cyberpro_remove,
+	remove:		__devexit_p(cyberpro_remove),
 	suspend:	cyberpro_suspend,
 	resume:		cyberpro_resume,
 	id_table:	cyberpro_pci_table
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- linux-2.4.16/drivers/video/imsttfb.c	Mon Nov 26 10:35:02 2001
+++ linux/drivers/video/imsttfb.c	Fri Dec  7 18:08:43 2001
@@ -1643,7 +1643,7 @@
 	name:		"imsttfb",
 	id_table:	imsttfb_pci_tbl,
 	probe:		imsttfb_probe,
-	remove:		imsttfb_remove,
+	remove:		__devexit_p(imsttfb_remove),
 };
 
 static struct fb_ops imsttfb_ops = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c
--- linux-2.4.16/drivers/video/matrox/matroxfb_base.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/matrox/matroxfb_base.c	Fri Dec  7 18:52:50 2001
@@ -108,6 +108,7 @@
 #endif
 
 static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
+int matroxfb_switch(int con, struct fb_info *info);
 
 /* --------------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/modedb.c linux/drivers/video/modedb.c
--- linux-2.4.16/drivers/video/modedb.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/modedb.c	Wed Dec  5 17:05:26 2001
@@ -41,7 +41,7 @@
 
 #define DEFAULT_MODEDB_INDEX	0
 
-static const struct fb_videomode modedb[] __initdata = {
+static struct fb_videomode modedb[] __initdata = {
     {
 	/* 640x400 @ 70 Hz, 31.5 kHz hsync */
 	NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c
--- linux-2.4.16/drivers/video/radeonfb.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/radeonfb.c	Fri Dec  7 18:08:43 2001
@@ -619,7 +619,7 @@
 	name:		"radeonfb",
 	id_table:	radeonfb_pci_table,
 	probe:		radeonfb_pci_register,
-	remove:		radeonfb_pci_unregister,
+	remove:		__devexit_p(radeonfb_pci_unregister),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c
--- linux-2.4.16/drivers/video/riva/fbdev.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/riva/fbdev.c	Fri Dec  7 18:08:43 2001
@@ -2082,7 +2082,7 @@
 	name:		"rivafb",
 	id_table:	rivafb_pci_tbl,
 	probe:		rivafb_init_one,
-	remove:		rivafb_remove_one,
+	remove:		__devexit_p(rivafb_remove_one),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- linux-2.4.16/drivers/video/tdfxfb.c	Mon Nov 26 10:35:03 2001
+++ linux/drivers/video/tdfxfb.c	Fri Dec  7 18:08:43 2001
@@ -495,7 +495,7 @@
 	name:		"tdfxfb",
 	id_table:	tdfxfb_id_table,
 	probe:		tdfxfb_probe,
-	remove:		tdfxfb_remove,
+	remove:		__devexit_p(tdfxfb_remove),
 };
 
 MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.16/fs/binfmt_elf.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/binfmt_elf.c	Thu Dec  6 19:57:21 2001
@@ -32,7 +32,7 @@
 #include <linux/highuid.h>
 #include <linux/smp_lock.h>
 #include <linux/compiler.h>
-#include <linux/limits.h>
+#include <linux/highmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
@@ -1032,6 +1032,25 @@
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
 
+	/* first copy the parameters from user space */
+	memset(&psinfo, 0, sizeof(psinfo));
+	{
+		int i, len;
+
+		len = current->mm->arg_end - current->mm->arg_start;
+		if (len >= ELF_PRARGSZ)
+			len = ELF_PRARGSZ-1;
+		copy_from_user(&psinfo.pr_psargs,
+			      (const char *)current->mm->arg_start, len);
+		for(i = 0; i < len; i++)
+			if (psinfo.pr_psargs[i] == 0)
+				psinfo.pr_psargs[i] = ' ';
+		psinfo.pr_psargs[len] = 0;
+
+	}
+
+	/* now stop all vm operations */
+	down_write(&current->mm->mmap_sem);
 	segs = current->mm->map_count;
 
 #ifdef DEBUG
@@ -1073,7 +1092,6 @@
 	 * Set up the notes in similar form to SVR4 core dumps made
 	 * with info from their /proc.
 	 */
-	memset(&psinfo, 0, sizeof(psinfo));
 	memset(&prstatus, 0, sizeof(prstatus));
 
 	notes[0].name = "CORE";
@@ -1129,23 +1147,6 @@
 	psinfo.pr_flag = current->flags;
 	psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
 	psinfo.pr_gid = NEW_TO_OLD_GID(current->gid);
-	{
-		int i, len;
-
-		set_fs(fs);
-
-		len = current->mm->arg_end - current->mm->arg_start;
-		if (len >= ELF_PRARGSZ)
-			len = ELF_PRARGSZ-1;
-		copy_from_user(&psinfo.pr_psargs,
-			      (const char *)current->mm->arg_start, len);
-		for(i = 0; i < len; i++)
-			if (psinfo.pr_psargs[i] == 0)
-				psinfo.pr_psargs[i] = ' ';
-		psinfo.pr_psargs[len] = 0;
-
-		set_fs(KERNEL_DS);
-	}
 	strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
 
 	notes[2].name = "CORE";
@@ -1217,8 +1218,6 @@
 		if (!writenote(&notes[i], file))
 			goto end_coredump;
 
-	set_fs(fs);
-
 	DUMP_SEEK(dataoff);
 
 	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
@@ -1232,22 +1231,24 @@
 		for (addr = vma->vm_start;
 		     addr < vma->vm_end;
 		     addr += PAGE_SIZE) {
-			pgd_t *pgd;
-			pmd_t *pmd;
-			pte_t *pte;
-
-			pgd = pgd_offset(vma->vm_mm, addr);
-			if (pgd_none(*pgd))
-				goto nextpage_coredump;
-			pmd = pmd_offset(pgd, addr);
-			if (pmd_none(*pmd))
-				goto nextpage_coredump;
-			pte = pte_offset(pmd, addr);
-			if (pte_none(*pte)) {
-nextpage_coredump:
+			struct page* page;
+			struct vm_area_struct *vma;
+
+			if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+						&page, &vma) <= 0) {
 				DUMP_SEEK (file->f_pos + PAGE_SIZE);
 			} else {
-				DUMP_WRITE((void*)addr, PAGE_SIZE);
+				if (page == ZERO_PAGE(addr)) {
+					DUMP_SEEK (file->f_pos + PAGE_SIZE);
+				} else {
+					void *kaddr;
+					flush_cache_page(vma, addr);
+					kaddr = kmap(page);
+					DUMP_WRITE(kaddr, PAGE_SIZE);
+					flush_page_to_ram(page);
+					kunmap(page);
+				}
+				put_page(page);
 			}
 		}
 	}
@@ -1260,6 +1261,7 @@
 
  end_coredump:
 	set_fs(fs);
+	up_write(&current->mm->mmap_sem);
 	return has_dumped;
 }
 #endif		/* USE_ELF_CORE_DUMP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/block_dev.c linux/fs/block_dev.c
--- linux-2.4.16/fs/block_dev.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/block_dev.c	Fri Dec  7 18:58:23 2001
@@ -234,7 +234,7 @@
 #define HASH_SIZE	(1UL << HASH_BITS)
 #define HASH_MASK	(HASH_SIZE-1)
 static struct list_head bdev_hashtable[HASH_SIZE];
-static spinlock_t bdev_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 static kmem_cache_t * bdev_cachep;
 
 #define alloc_bdev() \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.16/fs/buffer.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/buffer.c	Mon Dec 10 19:17:11 2001
@@ -73,7 +73,7 @@
 static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED;
 
 static struct buffer_head *lru_list[NR_LIST];
-static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t lru_list_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 static int nr_buffers_type[NR_LIST];
 static unsigned long size_buffers_type[NR_LIST];
 
@@ -1036,6 +1036,7 @@
 	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
 
 	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+	dirty += size_buffers_type[BUF_LOCKED] >> PAGE_SHIFT;
 	tot = nr_free_buffer_pages();
 
 	dirty *= 100;
@@ -2002,12 +2003,12 @@
 {
 	int i, nr_blocks, retval;
 	unsigned long * blocks = iobuf->blocks;
+	struct buffer_head bh;
 
+	bh.b_dev = inode->i_dev;
 	nr_blocks = iobuf->length / blocksize;
 	/* build the blocklist */
 	for (i = 0; i < nr_blocks; i++, blocknr++) {
-		struct buffer_head bh;
-
 		bh.b_state = 0;
 		bh.b_dev = inode->i_dev;
 		bh.b_size = blocksize;
@@ -2033,7 +2034,7 @@
 		blocks[i] = bh.b_blocknr;
 	}
 
-	retval = brw_kiovec(rw, 1, &iobuf, inode->i_dev, iobuf->blocks, blocksize);
+	retval = brw_kiovec(rw, 1, &iobuf, bh.b_dev, iobuf->blocks, blocksize);
 
  out:
 	return retval;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/cache.c linux/fs/coda/cache.c
--- linux-2.4.16/fs/coda/cache.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/cache.c	Wed Dec  5 16:28:13 2001
@@ -29,7 +29,6 @@
 void coda_cache_enter(struct inode *inode, int mask)
 {
 	struct coda_inode_info *cii = ITOC(inode);
-        ENTRY;
 
         if ( !coda_cred_ok(&cii->c_cached_cred) ) {
                 coda_load_creds(&cii->c_cached_cred);
@@ -42,7 +41,6 @@
 void coda_cache_clear_inode(struct inode *inode)
 {
 	struct coda_inode_info *cii = ITOC(inode);
-	ENTRY;
         cii->c_cached_perm = 0;
 }
 
@@ -53,7 +51,6 @@
         struct coda_inode_info *cii;
         struct list_head *tmp;
 
-        ENTRY;
         sbi = coda_sbp(sb);
         if (!sbi) BUG();
 
@@ -119,7 +116,6 @@
 {
 	struct dentry *alias_de;
 
-	ENTRY;
 	if ( !inode || !S_ISDIR(inode->i_mode)) 
 		return; 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/cnode.c linux/fs/coda/cnode.c
--- linux-2.4.16/fs/coda/cnode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/cnode.c	Wed Dec  5 16:28:13 2001
@@ -102,8 +102,6 @@
         struct coda_vattr attr;
         int error;
         
-        ENTRY;
-
 	/* We get inode numbers from Venus -- see venus source */
 	error = venus_getattr(sb, fid, &attr);
 	if ( error ) {
@@ -111,21 +109,18 @@
 		   "coda_cnode_make: coda_getvattr returned %d for %s.\n", 
 		   error, coda_f2s(fid));
 	    *inode = NULL;
-	    EXIT;
 	    return error;
 	} 
 
 	*inode = coda_iget(sb, fid, &attr);
 	if ( IS_ERR(*inode) ) {
 		printk("coda_cnode_make: coda_iget failed\n");
-		EXIT;
                 return PTR_ERR(*inode);
         }
 
 	CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n",
 		(*inode)->i_ino, atomic_read(&(*inode)->i_count), 
 		coda_f2s(&ITOC(*inode)->c_fid));
-        EXIT;
 	return 0;
 }
 
@@ -154,7 +149,6 @@
 	ino_t nr;
 	struct inode *inode;
 	struct coda_inode_info *cii;
-	ENTRY;
 
 	if ( !sb ) {
 		printk("coda_fid_to_inode: no sb!\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/dir.c linux/fs/coda/dir.c
--- linux-2.4.16/fs/coda/dir.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/dir.c	Wed Dec  5 16:28:13 2001
@@ -103,8 +103,6 @@
 	const char *name = entry->d_name.name;
 	size_t length = entry->d_name.len;
 	
-        ENTRY;
-
 	if ( length > CODA_MAXNAMLEN ) {
 	        printk("name too long: lookup, %s (%*s)\n", 
 		       coda_i2s(dir), (int)length, name);
@@ -154,7 +152,6 @@
 		d_drop(entry);
 		coda_flag_inode(res_inode, C_VATTR);
 	}
-        EXIT;
         return NULL;
 }
 
@@ -163,7 +160,6 @@
 {
         int error;
  
-        ENTRY;
 	coda_vfs_stat.permission++;
 
         if ( mask == 0 )
@@ -217,7 +213,6 @@
 	struct ViceFid newfid;
 	struct coda_vattr attrs;
 
-	ENTRY;
 	coda_vfs_stat.create++;
 
 	CDEBUG(D_INODE, "name: %s, length %d, mode %o\n", name, length, mode);
@@ -300,7 +295,6 @@
 	int error;
 	struct ViceFid newfid;
 
-	ENTRY;
 	coda_vfs_stat.mkdir++;
 
 	if (coda_isroot(dir) && coda_iscontrol(name, len))
@@ -344,7 +338,6 @@
 	int len = de->d_name.len;
 	int error;
 
-        ENTRY;
 	coda_vfs_stat.link++;
 
 	if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
@@ -368,7 +361,6 @@
         
 out:
 	CDEBUG(D_INODE, "link result %d\n",error);
-	EXIT;
 	return(error);
 }
 
@@ -381,7 +373,6 @@
 	int symlen;
         int error=0;
         
-        ENTRY;
 	coda_vfs_stat.symlink++;
 
 	if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
@@ -406,7 +397,6 @@
 		coda_dir_changed(dir_inode, 0);
 
         CDEBUG(D_INODE, "in symlink result %d\n",error);
-        EXIT;
         return error;
 }
 
@@ -417,7 +407,6 @@
 	const char *name = de->d_name.name;
 	int len = de->d_name.len;
 
-	ENTRY;
 	coda_vfs_stat.unlink++;
 
         CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name , 
@@ -441,7 +430,6 @@
 	int len = de->d_name.len;
         int error;
 
-	ENTRY;
 	coda_vfs_stat.rmdir++;
 
 	if (!d_unhashed(de))
@@ -471,7 +459,6 @@
         int link_adjust = 0;
         int error;
 
-	ENTRY;
 	coda_vfs_stat.rename++;
 
         CDEBUG(D_INODE, "old: %s, (%d length), new: %s"
@@ -499,7 +486,6 @@
 
 	CDEBUG(D_INODE, "result %d\n", error); 
 
-	EXIT;
 	return error;
 }
 
@@ -513,7 +499,6 @@
 	struct file *cfile, fakefile;
 	struct coda_inode_info *cii = ITOC(inode);
 
-        ENTRY;
 	coda_vfs_stat.readdir++;
 
         cfile = cii->c_container;
@@ -534,7 +519,6 @@
 		result = vfs_readdir(file, filldir, dirent);
         }
 
-        EXIT;
 	return result;
 }
 
@@ -549,6 +533,7 @@
 	fake_file->f_pos = coda_file->f_pos;
 	fake_file->f_version = coda_file->f_version;
 	fake_file->f_op = cont_dentry->d_inode->i_fop;
+	fake_file->f_flags = coda_file->f_flags;
 	return ;
 }
 
@@ -577,8 +562,6 @@
         int string_offset = (int) (&((struct venus_dirent *)(0))->d_name);
 	int i;
 
-        ENTRY;        
-
         CODA_ALLOC(buff, char *, DIR_BUFSIZE);
         if ( !buff ) { 
                 printk("coda_venus_readdir: out of memory.\n");
@@ -664,7 +647,6 @@
 {
 	struct inode *inode = de->d_inode;
 	struct coda_inode_info *cii;
-	ENTRY;
 
 	if (!inode)
 		return 1;
@@ -740,7 +722,6 @@
 	struct inode *inode = dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 
-	ENTRY;
 	CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
 	       dentry->d_name.len, dentry->d_name.name,
 	       dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/file.c linux/fs/coda/file.c
--- linux-2.4.16/fs/coda/file.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/file.c	Wed Dec  5 16:28:13 2001
@@ -102,7 +102,6 @@
 	struct coda_inode_info *cii;
 
 	lock_kernel();
-	ENTRY;
 	coda_vfs_stat.open++;
 
 	CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
@@ -140,7 +139,6 @@
 	       fh->f_dentry->d_inode->i_ino,
 	       atomic_read(&fh->f_dentry->d_inode->i_count),
                fh->f_dentry->d_inode->i_op);
-	EXIT;
 	unlock_kernel();
 	return 0;
 }
@@ -155,7 +153,6 @@
 	struct inode *cinode, *inode;
 	int err = 0, fcnt;
 
-	ENTRY;
 	coda_vfs_stat.flush++;
 
 	/* No need to make an upcall when we have not made any modifications
@@ -200,7 +197,6 @@
 	int err = 0;
 
 	lock_kernel();
-	ENTRY;
 	coda_vfs_stat.release++;
  
 	if (!use_coda_close) {
@@ -244,7 +240,6 @@
 	struct inode *cinode, *inode = dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 	int err = 0;
-	ENTRY;
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	      S_ISLNK(inode->i_mode)))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/inode.c linux/fs/coda/inode.c
--- linux-2.4.16/fs/coda/inode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/inode.c	Wed Dec  5 16:28:13 2001
@@ -99,7 +99,6 @@
         ViceFid fid;
         int error;
 	int idx;
-	ENTRY;
 
 	idx = get_device_index((struct coda_mount_data *) data);
 
@@ -112,19 +111,16 @@
 	vc = &coda_comms[idx];
 	if (!vc->vc_inuse) {
 		printk("coda_read_super: No pseudo device\n");
-		EXIT;  
 		return NULL;
 	}
 
         if ( vc->vc_sb ) {
 		printk("coda_read_super: Device already mounted\n");
-		EXIT;  
 		return NULL;
 	}
 
 	sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
 	if(!sbi) {
-		EXIT;  
 		return NULL;
 	}
 
@@ -159,11 +155,9 @@
 	printk("coda_read_super: rootinode is %ld dev %d\n", 
 	       root->i_ino, root->i_dev);
 	sb->s_root = d_alloc_root(root);
-	EXIT;  
         return sb;
 
  error:
-	EXIT;  
 	if (sbi) {
 		kfree(sbi);
 		if(vc)
@@ -179,16 +173,12 @@
 {
         struct coda_sb_info *sbi;
 
-        ENTRY;
-
 	sbi = coda_sbp(sb);
 	sbi->sbi_vcomm->vc_sb = NULL;
         list_del_init(&sbi->sbi_cihead);
 
 	printk("Coda: Bye bye.\n");
 	kfree(sbi);
-
-	EXIT;
 }
 
 /* all filling in of inodes postponed until lookup */
@@ -196,7 +186,6 @@
 {
 	struct coda_sb_info *sbi = coda_sbp(inode->i_sb);
 	struct coda_inode_info *cii;
-	ENTRY;
 
         if (!sbi) BUG();
 
@@ -229,7 +218,6 @@
 {
 	struct coda_inode_info *cii = ITOC(inode);
 
-        ENTRY;
         CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", 
 	       inode->i_ino, atomic_read(&inode->i_count));        
 	CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
@@ -244,8 +232,6 @@
 	cii_free(inode->u.generic_ip);
 	inode->u.generic_ip = NULL;
 #endif
-
-	EXIT;
 }
 
 int coda_notify_change(struct dentry *de, struct iattr *iattr)
@@ -254,7 +240,6 @@
         struct coda_vattr vattr;
         int error;
 	
-	ENTRY;
         memset(&vattr, 0, sizeof(vattr)); 
 
         coda_iattr_to_vattr(iattr, &vattr);
@@ -270,7 +255,6 @@
 	}
 	CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error);
 
-	EXIT;
 	return error;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/pioctl.c linux/fs/coda/pioctl.c
--- linux-2.4.16/fs/coda/pioctl.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/pioctl.c	Wed Dec  5 16:28:13 2001
@@ -45,8 +45,6 @@
 /* the coda pioctl inode ops */
 static int coda_ioctl_permission(struct inode *inode, int mask)
 {
-        ENTRY;
-
         return 0;
 }
 
@@ -59,7 +57,6 @@
         struct inode *target_inode = NULL;
         struct coda_inode_info *cnp;
 
-        ENTRY;
         /* get the Pioctl data arguments from user space */
         if (copy_from_user(&data, (int *)user_data, sizeof(data))) {
 	    return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/psdev.c linux/fs/coda/psdev.c
--- linux-2.4.16/fs/coda/psdev.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/psdev.c	Wed Dec  5 16:28:13 2001
@@ -292,7 +292,6 @@
 {
         struct venus_comm *vcp;
 	int idx;
-        ENTRY;
 
 	lock_kernel();
 	idx = MINOR(inode->i_rdev);
@@ -319,7 +318,6 @@
 
 	CDEBUG(D_PSDEV, "device %i - inuse: %d\n", idx, vcp->vc_inuse);
 
-	EXIT;
 	unlock_kernel();
         return 0;
 }
@@ -330,7 +328,6 @@
         struct venus_comm *vcp = (struct venus_comm *) file->private_data;
         struct upc_req *req;
 	struct list_head *lh, *next;
-	ENTRY;
 
 	lock_kernel();
 	if ( !vcp->vc_inuse ) {
@@ -371,7 +368,6 @@
         }
 	CDEBUG(D_PSDEV, "Done.\n");
 
-	EXIT;
 	unlock_kernel();
 	return 0;
 }
@@ -410,6 +406,7 @@
 
 
 MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
+MODULE_LICENSE("GPL");
 
 static int __init init_coda(void)
 {
@@ -435,8 +432,6 @@
 static void __exit exit_coda(void)
 {
         int err;
-
-        ENTRY;
 
 	err = unregister_filesystem(&coda_fs_type);
         if ( err != 0 ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/sysctl.c linux/fs/coda/sysctl.c
--- linux-2.4.16/fs/coda/sysctl.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/sysctl.c	Wed Dec  5 16:28:13 2001
@@ -359,7 +359,6 @@
 	char tmpbuf[80];
 	int tmplen = 0;
 
-	ENTRY;
 	/* this works as long as we are below 1024 characters! */
 	if ( offset < 80 ) 
 		len += sprintf( buffer,"%-79s\n",	"Coda upcall statistics");
@@ -392,7 +391,7 @@
 		len = length;
 	if ( len < 0 )
 		len = 0;
-	EXIT;
+
 	return len;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/coda/upcall.c linux/fs/coda/upcall.c
--- linux-2.4.16/fs/coda/upcall.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/coda/upcall.c	Wed Dec  5 16:28:13 2001
@@ -80,7 +80,6 @@
         union inputArgs *inp;
         union outputArgs *outp;
         int insize, outsize, error;
-	ENTRY;
 
         insize = SIZE(root);
         UPARG(CODA_ROOT);
@@ -96,7 +95,6 @@
 	}
 
 	CODA_FREE(inp, insize);
-        EXIT;
 	return error;
 }
 
@@ -106,7 +104,6 @@
         union inputArgs *inp;
         union outputArgs *outp;
         int insize, outsize, error;
-	ENTRY;
 
         insize = SIZE(getattr); 
 	UPARG(CODA_GETATTR);
@@ -117,7 +114,6 @@
 	*attr = outp->coda_getattr.attr;
 
 	CODA_FREE(inp, insize);
-        EXIT;
         return error;
 }
 
@@ -432,7 +428,6 @@
 	}
         
         CDEBUG(D_INODE, " result %d\n",error);
-        EXIT;
         CODA_FREE(inp, insize);
         return error;
 }
@@ -462,7 +457,6 @@
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
         CDEBUG(D_INODE, " result %d\n",error);
-        EXIT;
 	CODA_FREE(inp, insize);
         return error;
 }
@@ -499,7 +493,6 @@
 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
         CDEBUG(D_INODE, " result %d\n",error);
-        EXIT;
 	CODA_FREE(inp, insize);
         return error;
 }
@@ -536,7 +529,6 @@
 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
 	CODA_FREE(inp, insize);
-        EXIT;
 	return error;
 }
 
@@ -633,7 +625,6 @@
 	}
 
         CDEBUG(D_INODE, " result %d\n",error);
-        EXIT;
         CODA_FREE(inp, insize);
         return error;
 }
@@ -721,8 +712,6 @@
 	union outputArgs *out;
 	struct upc_req *req;
 	int error = 0;
-
-	ENTRY;
 
 	vcommp = sbi->sbi_vcomm;
 	if ( !vcommp->vc_inuse ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- linux-2.4.16/fs/cramfs/inode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/cramfs/inode.c	Wed Dec  5 16:41:08 2001
@@ -19,6 +19,7 @@
 #include <linux/locks.h>
 #include <linux/blkdev.h>
 #include <linux/cramfs_fs.h>
+#include <asm/semaphore.h>
 
 #include <asm/uaccess.h>
 
@@ -33,6 +34,9 @@
 static struct file_operations cramfs_directory_operations;
 static struct address_space_operations cramfs_aops;
 
+static DECLARE_MUTEX(read_mutex);
+
+
 /* These two macros may change in future, to provide better st_ino
    semantics. */
 #define CRAMINO(x)	((x)->offset?(x)->offset<<2:1)
@@ -199,8 +203,10 @@
 	for (i = 0; i < READ_BUFFERS; i++)
 		buffer_blocknr[i] = -1;
 
+	down(&read_mutex);
 	/* Read the first block and get the superblock from it */
 	memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
+	up(&read_mutex);
 
 	/* Do sanity checks on the superblock */
 	if (super.magic != CRAMFS_MAGIC) {
@@ -291,7 +297,9 @@
 		char *name;
 		int namelen, error;
 
+		down(&read_mutex);
 		de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
+		up(&read_mutex);
 		name = (char *)(de+1);
 
 		/*
@@ -332,7 +340,9 @@
 		char *name;
 		int namelen, retval;
 
+		down(&read_mutex);
 		de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256);
+		up(&read_mutex);
 		name = (char *)(de+1);
 
 		/* Try to take advantage of sorted directories */
@@ -384,18 +394,22 @@
 		u32 start_offset, compr_len;
 
 		start_offset = OFFSET(inode) + maxblock*4;
+		down(&read_mutex);
 		if (page->index)
 			start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
-		compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4)
-			     - start_offset);
+		compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
+		up(&read_mutex);
 		pgdata = kmap(page);
 		if (compr_len == 0)
 			; /* hole */
-		else
+		else {
+			down(&read_mutex);
 			bytes_filled = cramfs_uncompress_block(pgdata,
 				 PAGE_CACHE_SIZE,
 				 cramfs_read(sb, start_offset, compr_len),
 				 compr_len);
+			up(&read_mutex);
+		}
 	} else
 		pgdata = kmap(page);
 	memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/dcache.c linux/fs/dcache.c
--- linux-2.4.16/fs/dcache.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/dcache.c	Fri Dec  7 18:58:23 2001
@@ -29,7 +29,7 @@
 #define DCACHE_PARANOIA 1
 /* #define DCACHE_DEBUG 1 */
 
-spinlock_t dcache_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* Right now the dcache depends on the kernel lock */
 #define check_lock()	if (!kernel_locked()) BUG()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/devfs/base.c linux/fs/devfs/base.c
--- linux-2.4.16/fs/devfs/base.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/devfs/base.c	Wed Dec  5 20:26:17 2001
@@ -427,7 +427,7 @@
 	       Work sponsored by SGI.
   v0.92
     20000306   Richard Gooch <rgooch@atnf.csiro.au>
-	       Added DEVFS_FL_NO_PERSISTENCE flag.
+	       Added DEVFS_ FL_NO_PERSISTENCE flag.
 	       Removed unnecessary call to <update_devfs_inode_from_entry> in
 	       <devfs_readdir>.
 	       Work sponsored by SGI.
@@ -545,21 +545,40 @@
     20010919   Richard Gooch <rgooch@atnf.csiro.au>
 	       Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>.
   v0.116
-    20010927   Richard Gooch <rgooch@atnf.csiro.au>
-	       Went back to global rwsem for symlinks (refcount scheme no good)
-  v0.117
     20011008   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed overrun in <devfs_link> by removing function (not needed).
-  v0.118
     20011009   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed buffer underrun in <try_modload>.
-	       Moved down_read() from <search_for_entry_in_dir> to <find_entry>
-  v0.119
     20011029   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed race in <devfsd_ioctl> when setting event mask.
-    20011103   Richard Gooch <rgooch@atnf.csiro.au>
-	       Avoid deadlock in <devfs_follow_link> by using temporary buffer.
-  v0.120
+    20011114   Richard Gooch <rgooch@atnf.csiro.au>
+	       First release of new locking code.
+  v1.0
+    20011117   Richard Gooch <rgooch@atnf.csiro.au>
+	       Discard temporary buffer, now use "%s" for dentry names.
+    20011118   Richard Gooch <rgooch@atnf.csiro.au>
+	       Don't generate path in <try_modload>: use fake entry instead.
+	       Use "existing" directory in <_devfs_make_parent_for_leaf>.
+    20011122   Richard Gooch <rgooch@atnf.csiro.au>
+	       Use slab cache rather than fixed buffer for devfsd events.
+  v1.1
+    20011125   Richard Gooch <rgooch@atnf.csiro.au>
+	       Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>.
+    20011127   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed locking bug in <devfs_d_revalidate_wait> due to typo.
+	       Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from
+	       devfsd or children.
+  v1.2
+    20011202   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed bug in <devfsd_read>: was dereferencing freed pointer.
+  v1.3
+    20011203   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed bug in <devfsd_close>: was dereferencing freed pointer.
+	       Added process group check for devfsd privileges.
+  v1.4
+    20011204   Richard Gooch <rgooch@atnf.csiro.au>
+	       Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>.
+  v1.5
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -592,7 +611,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.120 (20011103)"
+#define DEVFS_VERSION            "1.5 (20011204)"
 
 #define DEVFS_NAME "devfs"
 
@@ -605,27 +624,30 @@
 #  define FALSE 0
 #endif
 
-#define IS_HIDDEN(de) (( ((de)->hide && !is_devfsd_or_child(fs_info)) || !(de)->registered))
+#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO)
 
-#define DEBUG_NONE         0x00000
-#define DEBUG_MODULE_LOAD  0x00001
-#define DEBUG_REGISTER     0x00002
-#define DEBUG_UNREGISTER   0x00004
-#define DEBUG_SET_FLAGS    0x00008
-#define DEBUG_S_PUT        0x00010
-#define DEBUG_I_LOOKUP     0x00020
-#define DEBUG_I_CREATE     0x00040
-#define DEBUG_I_GET        0x00080
-#define DEBUG_I_CHANGE     0x00100
-#define DEBUG_I_UNLINK     0x00200
-#define DEBUG_I_RLINK      0x00400
-#define DEBUG_I_FLINK      0x00800
-#define DEBUG_I_MKNOD      0x01000
-#define DEBUG_F_READDIR    0x02000
-#define DEBUG_D_DELETE     0x04000
-#define DEBUG_D_RELEASE    0x08000
-#define DEBUG_D_IPUT       0x10000
-#define DEBUG_ALL          0xfffff
+#define IS_HIDDEN(de) ( (de)->hide && !is_devfsd_or_child(fs_info) )
+
+#define DEBUG_NONE         0x0000000
+#define DEBUG_MODULE_LOAD  0x0000001
+#define DEBUG_REGISTER     0x0000002
+#define DEBUG_UNREGISTER   0x0000004
+#define DEBUG_FREE         0x0000008
+#define DEBUG_SET_FLAGS    0x0000010
+#define DEBUG_S_READ       0x0000100        /*  Break  */
+#define DEBUG_I_LOOKUP     0x0001000        /*  Break  */
+#define DEBUG_I_CREATE     0x0002000
+#define DEBUG_I_GET        0x0004000
+#define DEBUG_I_CHANGE     0x0008000
+#define DEBUG_I_UNLINK     0x0010000
+#define DEBUG_I_RLINK      0x0020000
+#define DEBUG_I_FLINK      0x0040000
+#define DEBUG_I_MKNOD      0x0080000
+#define DEBUG_F_READDIR    0x0100000        /*  Break  */
+#define DEBUG_D_DELETE     0x1000000        /*  Break  */
+#define DEBUG_D_RELEASE    0x2000000
+#define DEBUG_D_IPUT       0x4000000
+#define DEBUG_ALL          0xfffffff
 #define DEBUG_DISABLED     DEBUG_NONE
 
 #define OPTION_NONE             0x00
@@ -638,9 +660,11 @@
 
 struct directory_type
 {
+    rwlock_t lock;                   /*  Lock for searching(R)/updating(W)   */
     struct devfs_entry *first;
     struct devfs_entry *last;
-    unsigned int num_removable;
+    unsigned short num_removable;    /*  Lock for writing but not reading    */
+    unsigned char no_more_additions:1;
 };
 
 struct file_type
@@ -656,8 +680,6 @@
 
 struct fcb_type  /*  File, char, block type  */
 {
-    uid_t default_uid;
-    gid_t default_gid;
     void *ops;
     union 
     {
@@ -678,20 +700,13 @@
     char *linkname;              /*  This is NULL-terminated                 */
 };
 
-struct fifo_type
-{
-    uid_t uid;
-    gid_t gid;
-};
-
-struct devfs_inode  /*  This structure is for "persistent" inode storage  */
+struct devfs_inode     /*  This structure is for "persistent" inode storage  */
 {
+    struct dentry *dentry;
     time_t atime;
     time_t mtime;
     time_t ctime;
-    unsigned int ino;          /*  Inode number as seen in the VFS  */
-    struct dentry *dentry;
-    umode_t mode;
+    unsigned int ino;            /*  Inode number as seen in the VFS         */
     uid_t uid;
     gid_t gid;
 };
@@ -699,12 +714,13 @@
 struct devfs_entry
 {
     void *info;
+    atomic_t refcount;           /*  When this drops to zero, it's unused    */
     union 
     {
 	struct directory_type dir;
 	struct fcb_type fcb;
 	struct symlink_type symlink;
-	struct fifo_type fifo;
+	const char *name;        /*  Only used for (mode == 0)               */
     }
     u;
     struct devfs_entry *prev;    /*  Previous entry in the parent directory  */
@@ -713,12 +729,11 @@
     struct devfs_entry *slave;   /*  Another entry to unregister             */
     struct devfs_inode inode;
     umode_t mode;
-    unsigned short namelen;  /*  I think 64k+ filenames are a way off...  */
-    unsigned char registered:1;
+    unsigned short namelen;      /*  I think 64k+ filenames are a way off... */
     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  */
+    unsigned char vfs_created:1; /*  Whether created by driver or VFS        */
+    char name[1];                /*  This is just a dummy: the allocated array
+				     is bigger. This is NULL-terminated      */
 };
 
 /*  The root of the device tree  */
@@ -726,35 +741,39 @@
 
 struct devfsd_buf_entry
 {
-    void *data;
-    unsigned int type;
+    struct devfs_entry *de;      /*  The name is generated with this         */
+    unsigned short type;         /*  The type of event                       */
     umode_t mode;
     uid_t uid;
     gid_t gid;
+    struct devfsd_buf_entry *next;
 };
 
-struct fs_info      /*  This structure is for the mounted devfs  */
+struct fs_info                  /*  This structure is for the mounted devfs  */
 {
     struct super_block *sb;
-    volatile struct devfsd_buf_entry *devfsd_buffer;
-    spinlock_t devfsd_buffer_lock;
-    volatile unsigned int devfsd_buf_in;
-    volatile unsigned int devfsd_buf_out;
+    spinlock_t devfsd_buffer_lock;  /*  Lock when inserting/deleting events  */
+    struct devfsd_buf_entry *devfsd_first_event;
+    struct devfsd_buf_entry *devfsd_last_event;
     volatile int devfsd_sleeping;
     volatile struct task_struct *devfsd_task;
+    volatile pid_t devfsd_pgrp;
     volatile struct file *devfsd_file;
     struct devfsd_notify_struct *devfsd_info;
     volatile unsigned long devfsd_event_mask;
     atomic_t devfsd_overrun_count;
-    wait_queue_head_t devfsd_wait_queue;
-    wait_queue_head_t revalidate_wait_queue;
+    wait_queue_head_t devfsd_wait_queue;      /*  Wake devfsd on input       */
+    wait_queue_head_t revalidate_wait_queue;  /*  Wake when devfsd sleeps    */
 };
 
 static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};
-static const int devfsd_buf_size = PAGE_SIZE / sizeof(struct devfsd_buf_entry);
+static kmem_cache_t *devfsd_buf_cache;
 #ifdef CONFIG_DEVFS_DEBUG
 static unsigned int devfs_debug_init __initdata = DEBUG_NONE;
 static unsigned int devfs_debug = DEBUG_NONE;
+static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int stat_num_entries;
+static unsigned int stat_num_bytes;
 #endif
 
 #ifdef CONFIG_DEVFS_MOUNT
@@ -763,19 +782,23 @@
 static unsigned int boot_options = OPTION_NONE;
 #endif
 
-static DECLARE_RWSEM (symlink_rwsem);
-
 /*  Forward function declarations  */
-static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
-					     const char *name,
-					     unsigned int namelen, int mkdir,
-					     int mkfile, int *is_new,
-					     int traverse_symlink);
+static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
+					const char *name, int namelen,
+					int traverse_symlink);
 static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
 			    loff_t *ppos);
 static int devfsd_ioctl (struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg);
 static int devfsd_close (struct inode *inode, struct file *file);
+#ifdef CONFIG_DEVFS_DEBUG
+static int stat_read (struct file *file, char *buf, size_t len,
+			    loff_t *ppos);
+static struct file_operations stat_fops =
+{
+    read:    stat_read,
+};
+#endif
 
 
 /*  Devfs daemon file operations  */
@@ -791,46 +814,95 @@
 
 
 /**
- *	search_for_entry_in_dir - Search for a devfs entry inside another devfs entry.
- *	@parent:  The parent devfs entry.
- *	@name:  The name of the entry.
+ *	devfs_get - Get a reference to a devfs entry.
+ *	@de:  The devfs entry.
+ */
+
+static struct devfs_entry *devfs_get (struct devfs_entry *de)
+{
+    if (de) atomic_inc (&de->refcount);
+    return de;
+}   /*  End Function devfs_get  */
+
+/**
+ *	devfs_put - Put (release) a reference to a devfs entry.
+ *	@de:  The devfs entry.
+ */
+
+static void devfs_put (struct devfs_entry *de)
+{
+    if (!de) return;
+    if ( !atomic_dec_and_test (&de->refcount) ) return;
+    if (de == root_entry)
+	OOPS ("%s: devfs_put(): root entry being freed\n", DEVFS_NAME);
+#ifdef CONFIG_DEVFS_DEBUG
+    if (devfs_debug & DEBUG_FREE)
+	printk ("%s: devfs_put(%s): de: %p, parent: %p \"%s\"\n",
+		DEVFS_NAME, de->name, de, de->parent,
+		de->parent ? de->parent->name : "no parent");
+#endif
+    if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
+    if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen )
+    {
+	devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
+			       DEVFS_SPECIAL_BLK,
+			       MKDEV (de->u.fcb.u.device.major,
+				      de->u.fcb.u.device.minor) );
+    }
+#ifdef CONFIG_DEVFS_DEBUG
+    spin_lock (&stat_lock);
+    --stat_num_entries;
+    stat_num_bytes -= sizeof *de + de->namelen;
+    if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1;
+    spin_unlock (&stat_lock);
+#endif
+    kfree (de);
+}   /*  End Function devfs_put  */
+
+/**
+ *	_devfs_search_dir - Search for a devfs entry in a directory.
+ *	@dir:  The directory to search.
+ *	@name:  The name of the entry to search for.
  *	@namelen:  The number of characters in @name.
- *	@traverse_symlink:  If %TRUE then the entry is traversed if it is a symlink.
  *
- *  Search for a devfs entry inside another devfs entry and returns a pointer
- *   to the entry on success, else %NULL.
+ *  Search for a devfs entry in a directory and returns a pointer to the entry
+ *   on success, else %NULL. The directory must be locked already.
+ *   An implicit devfs_get() is performed on the returned entry.
  */
 
-static struct devfs_entry *search_for_entry_in_dir (struct devfs_entry *parent,
-						    const char *name,
-						    unsigned int namelen,
-						    int traverse_symlink)
+static struct devfs_entry *_devfs_search_dir (struct devfs_entry *dir,
+					      const char *name,
+					      unsigned int namelen)
 {
-    struct devfs_entry *curr, *retval;
+    struct devfs_entry *curr;
 
-    if ( !S_ISDIR (parent->mode) )
+    if ( !S_ISDIR (dir->mode) )
     {
-	printk ("%s: entry is not a directory\n", DEVFS_NAME);
+	printk ("%s: search_dir(%s): not a directory\n", DEVFS_NAME,dir->name);
 	return NULL;
     }
-    for (curr = parent->u.dir.first; curr != NULL; curr = curr->next)
+    for (curr = dir->u.dir.first; curr != NULL; curr = curr->next)
     {
 	if (curr->namelen != namelen) continue;
 	if (memcmp (curr->name, name, namelen) == 0) break;
 	/*  Not found: try the next one  */
     }
-    if (curr == NULL) return NULL;
-    if (!S_ISLNK (curr->mode) || !traverse_symlink) return curr;
-    /*  Need to follow the link: this is a stack chomper  */
-    retval = curr->registered ?
-	search_for_entry (parent, curr->u.symlink.linkname,
-			  curr->u.symlink.length, FALSE, FALSE, NULL,
-			  TRUE) : NULL;
-    return retval;
-}   /*  End Function search_for_entry_in_dir  */
+    return devfs_get (curr);
+}   /*  End Function _devfs_search_dir  */
+
+
+/**
+ *	_devfs_alloc_entry - Allocate a devfs entry.
+ *	@name:  The name of the entry.
+ *	@namelen:  The number of characters in @name.
+ *
+ *  Allocate a devfs entry and returns a pointer to the entry on success, else
+ *   %NULL.
+ */
 
-static struct devfs_entry *create_entry (struct devfs_entry *parent,
-					 const char *name,unsigned int namelen)
+static struct devfs_entry *_devfs_alloc_entry (const char *name,
+					       unsigned int namelen,
+					       umode_t mode)
 {
     struct devfs_entry *new;
     static unsigned long inode_counter = FIRST_INODE;
@@ -839,168 +911,270 @@
     if ( name && (namelen < 1) ) namelen = strlen (name);
     if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL )
 	return NULL;
-    /*  Magic: this will set the ctime to zero, thus subsequent lookups will
-	trigger the call to <update_devfs_inode_from_entry>  */
     memset (new, 0, sizeof *new + namelen);
+    new->mode = mode;
+    if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock);
+    atomic_set (&new->refcount, 1);
     spin_lock (&counter_lock);
     new->inode.ino = inode_counter++;
     spin_unlock (&counter_lock);
-    new->parent = parent;
     if (name) memcpy (new->name, name, namelen);
     new->namelen = namelen;
-    if (parent == NULL) return new;
-    new->prev = parent->u.dir.last;
-    /*  Insert into the parent directory's list of children  */
-    if (parent->u.dir.first == NULL) parent->u.dir.first = new;
-    else parent->u.dir.last->next = new;
-    parent->u.dir.last = new;
+#ifdef CONFIG_DEVFS_DEBUG
+    spin_lock (&stat_lock);
+    ++stat_num_entries;
+    stat_num_bytes += sizeof *new + namelen;
+    spin_unlock (&stat_lock);
+#endif
     return new;
-}   /*  End Function create_entry  */
+}   /*  End Function _devfs_alloc_entry  */
+
 
-static void update_devfs_inode_from_entry (struct devfs_entry *de)
+/**
+ *	_devfs_append_entry - Append a devfs entry to a directory's child list.
+ *	@dir:  The directory to add to.
+ *	@de:  The devfs entry to append.
+ *	@removable: If TRUE, increment the count of removable devices for %dir.
+ *	@old_de: If an existing entry exists, it will be written here. This may
+ *		 be %NULL.
+ *
+ *  Append a devfs entry to a directory's list of children, checking first to
+ *   see if an entry of the same name exists. The directory will be locked.
+ *   The value 0 is returned on success, else a negative error code.
+ *   On failure, an implicit devfs_put() is performed on %de.
+ */
+
+static int _devfs_append_entry (devfs_handle_t dir, devfs_handle_t de,
+				int removable, devfs_handle_t *old_de)
 {
-    if (de == NULL) return;
-    if ( S_ISDIR (de->mode) )
-    {
-	de->inode.mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
-	de->inode.uid = 0;
-	de->inode.gid = 0;
-    }
-    else if ( S_ISLNK (de->mode) )
-    {
-	de->inode.mode = S_IFLNK | S_IRUGO | S_IXUGO;
-	de->inode.uid = 0;
-	de->inode.gid = 0;
-    }
-    else if ( S_ISFIFO (de->mode) )
+    int retval;
+
+    if (old_de) *old_de = NULL;
+    if ( !S_ISDIR (dir->mode) )
     {
-	de->inode.mode = de->mode;
-	de->inode.uid = de->u.fifo.uid;
-	de->inode.gid = de->u.fifo.gid;
+	printk ("%s: append_entry(%s): dir: \"%s\" is not a directory\n",
+		DEVFS_NAME, de->name, dir->name);
+	devfs_put (de);
+	return -ENOTDIR;
     }
+    write_lock (&dir->u.dir.lock);
+    if (dir->u.dir.no_more_additions) retval = -ENOENT;
     else
     {
-	if (de->u.fcb.auto_owner)
-	    de->inode.mode = (de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
-	else de->inode.mode = de->mode;
-	de->inode.uid = de->u.fcb.default_uid;
-	de->inode.gid = de->u.fcb.default_gid;
+	struct devfs_entry *old;
+
+	old = _devfs_search_dir (dir, de->name, de->namelen);
+	if (old_de) *old_de = old;
+	else devfs_put (old);
+	if (old == NULL)
+	{
+	    de->parent = dir;
+	    de->prev = dir->u.dir.last;
+	    /*  Append to the directory's list of children  */
+	    if (dir->u.dir.first == NULL) dir->u.dir.first = de;
+	    else dir->u.dir.last->next = de;
+	    dir->u.dir.last = de;
+	    if (removable) ++dir->u.dir.num_removable;
+	    retval = 0;
+	}
+	else retval = -EEXIST;
     }
-}   /*  End Function update_devfs_inode_from_entry  */
+    write_unlock (&dir->u.dir.lock);
+    if (retval) devfs_put (de);
+    return retval;
+}   /*  End Function _devfs_append_entry  */
+
 
 /**
- *	get_root_entry - Get the root devfs entry.
+ *	_devfs_get_root_entry - Get the root devfs entry.
  *
  *	Returns the root devfs entry on success, else %NULL.
  */
 
-static struct devfs_entry *get_root_entry (void)
+static struct devfs_entry *_devfs_get_root_entry (void)
 {
     kdev_t devnum;
     struct devfs_entry *new;
+    static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
 
     /*  Always ensure the root is created  */
-    if (root_entry != NULL) return root_entry;
-    if ( ( root_entry = create_entry (NULL, NULL, 0) ) == NULL ) return NULL;
-    root_entry->mode = S_IFDIR;
-    /*  Force an inode update, because lookup() is never done for the root  */
-    update_devfs_inode_from_entry (root_entry);
-    root_entry->registered = TRUE;
+    if (root_entry) return root_entry;
+    if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL;
+    spin_lock (&root_lock);
+    if (root_entry)
+    {
+	spin_unlock (&root_lock);
+	devfs_put (new);
+	return (root_entry);
+    }
+    root_entry = new;
+    spin_unlock (&root_lock);
     /*  And create the entry for ".devfsd"  */
-    if ( ( new = create_entry (root_entry, ".devfsd", 0) ) == NULL )
-	return NULL;
+    if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
+	 == NULL ) return NULL;
     devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
     new->u.fcb.u.device.major = MAJOR (devnum);
     new->u.fcb.u.device.minor = MINOR (devnum);
-    new->mode = S_IFCHR | S_IRUSR | S_IWUSR;
-    new->u.fcb.default_uid = 0;
-    new->u.fcb.default_gid = 0;
     new->u.fcb.ops = &devfsd_fops;
-    new->registered = TRUE;
+    _devfs_append_entry (root_entry, new, FALSE, NULL);
+#ifdef CONFIG_DEVFS_DEBUG
+    if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
+	 == NULL ) return NULL;
+    devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
+    new->u.fcb.u.device.major = MAJOR (devnum);
+    new->u.fcb.u.device.minor = MINOR (devnum);
+    new->u.fcb.ops = &stat_fops;
+    _devfs_append_entry (root_entry, new, FALSE, NULL);
+#endif
     return root_entry;
-}   /*  End Function get_root_entry  */
+}   /*  End Function _devfs_get_root_entry  */
 
 
 /**
- *	search_for_entry - Search for an entry in the devfs tree.
- *	@dir: The parent directory to search from. If this is %NULL the root is used
- *	@name: The name of the entry.
- *	@namelen: The number of characters in @name.
- *	@mkdir: If %TRUE intermediate directories are created as needed.
- *	@mkfile: If %TRUE the file entry is created if it doesn't exist.
- *	@is_new: If the returned entry was newly made, %TRUE is written here. If
- * 		this is %NULL nothing is written here.
- *	@traverse_symlink: If %TRUE then symbolic links are traversed.
+ *	_devfs_descend - Descend down a tree using the next component name.
+ *	@dir:  The directory to search.
+ *	@name:  The component name to search for.
+ *	@namelen:  The length of %name.
+ *	@next_pos:  The position of the next '/' or '\0' is written here.
  *
- *	If the entry is created, then it will be in the unregistered state.
- *	Returns a pointer to the entry on success, else %NULL.
+ *  Descend into a directory, searching for a component. This function forms
+ *   the core of a tree-walking algorithm. The directory will be locked.
+ *   The devfs entry corresponding to the component is returned. If there is
+ *   no matching entry, %NULL is returned.
+ *   An implicit devfs_get() is performed on the returned entry.
  */
 
-static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
-					     const char *name,
-					     unsigned int namelen, int mkdir,
-					     int mkfile, int *is_new,
-					     int traverse_symlink)
+static struct devfs_entry *_devfs_descend (struct devfs_entry *dir,
+					   const char *name, int namelen,
+					   int *next_pos)
 {
-    int len;
-    const char *subname, *stop, *ptr;
+    const char *stop, *ptr;
     struct devfs_entry *entry;
 
-    if (is_new) *is_new = FALSE;
-    if (dir == NULL) dir = get_root_entry ();
-    if (dir == NULL) return NULL;
-    /*  Extract one filename component  */
-    subname = name;
+    if ( (namelen >= 3) && (strncmp (name, "../", 3) == 0) )
+    {   /*  Special-case going to parent directory  */
+	*next_pos = 3;
+	return devfs_get (dir->parent);
+    }
     stop = name + namelen;
-    while (subname < stop)
-    {
-	/*  Search for a possible '/'  */
-	for (ptr = subname; (ptr < stop) && (*ptr != '/'); ++ptr);
-	if (ptr >= stop)
-	{
-	    /*  Look for trailing component  */
-	    len = stop - subname;
-	    entry = search_for_entry_in_dir (dir, subname, len,
-					     traverse_symlink);
-	    if (entry != NULL) return entry;
-	    if (!mkfile) return NULL;
-	    entry = create_entry (dir, subname, len);
-	    if (entry && is_new) *is_new = TRUE;
-	    return entry;
-	}
-	/*  Found '/': search for directory  */
-	if (strncmp (subname, "../", 3) == 0)
-	{
-	    /*  Going up  */
-	    dir = dir->parent;
-	    if (dir == NULL) return NULL;  /*  Cannot escape from devfs  */
-	    subname += 3;
-	    continue;
+    /*  Search for a possible '/'  */
+    for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr);
+    *next_pos = ptr - name;
+    read_lock (&dir->u.dir.lock);
+    entry = _devfs_search_dir (dir, name, *next_pos);
+    read_unlock (&dir->u.dir.lock);
+    return entry;
+}   /*  End Function _devfs_descend  */
+
+
+static devfs_handle_t _devfs_make_parent_for_leaf (struct devfs_entry *dir,
+						   const char *name,
+						   int namelen, int *leaf_pos)
+{
+    int next_pos = 0;
+
+    if (dir == NULL) dir = _devfs_get_root_entry ();
+    if (dir == NULL) return NULL;
+    devfs_get (dir);
+    /*  Search for possible trailing component and ignore it  */
+    for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen);
+    *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0;
+    for (; namelen > 0; name += next_pos, namelen -= next_pos)
+    {
+	struct devfs_entry *de, *old;
+
+	if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
+	{
+	    de = _devfs_alloc_entry (name, next_pos, MODE_DIR);
+	    devfs_get (de);
+	    if ( !de || _devfs_append_entry (dir, de, FALSE, &old) )
+	    {
+		devfs_put (de);
+		if ( !old || !S_ISDIR (old->mode) )
+		{
+		    devfs_put (old);
+		    devfs_put (dir);
+		    return NULL;
+		}
+		de = old;  /*  Use the existing directory  */
+	    }
 	}
-	len = ptr - subname;
-	entry = search_for_entry_in_dir (dir, subname, len, traverse_symlink);
-	if (!entry && !mkdir) return NULL;
-	if (entry == NULL)
+	if (de == dir->parent)
 	{
-	    /*  Make it  */
-	    if ( ( entry = create_entry (dir, subname, len) ) == NULL )
-		return NULL;
-	    entry->mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
-	    if (is_new) *is_new = TRUE;
+	    devfs_put (dir);
+	    devfs_put (de);
+	    return NULL;
 	}
-	if ( !S_ISDIR (entry->mode) )
+	devfs_put (dir);
+	dir = de;
+	if (name[next_pos] == '/') ++next_pos;
+    }
+    return dir;
+}   /*  End Function _devfs_make_parent_for_leaf  */
+
+
+static devfs_handle_t _devfs_prepare_leaf (devfs_handle_t *dir,
+					   const char *name, umode_t mode)
+{
+    int namelen, leaf_pos;
+    struct devfs_entry *de;
+
+    namelen = strlen (name);
+    if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen,
+					       &leaf_pos) ) == NULL )
+    {
+	printk ("%s: prepare_leaf(%s): could not create parent path\n",
+		DEVFS_NAME, name);
+	return NULL;
+    }
+    if ( ( de = _devfs_alloc_entry (name + leaf_pos, namelen - leaf_pos,mode) )
+	 == NULL )
+    {
+	printk ("%s: prepare_leaf(%s): could not allocate entry\n",
+		DEVFS_NAME, name);
+	devfs_put (*dir);
+	return NULL;
+    }
+    return de;
+}   /*  End Function _devfs_prepare_leaf  */
+
+
+static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
+					const char *name, int namelen,
+					int traverse_symlink)
+{
+    int next_pos = 0;
+
+    if (dir == NULL) dir = _devfs_get_root_entry ();
+    if (dir == NULL) return NULL;
+    devfs_get (dir);
+    for (; namelen > 0; name += next_pos, namelen -= next_pos)
+    {
+	struct devfs_entry *de, *link;
+
+	if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
 	{
-	    printk ("%s: existing non-directory entry\n", DEVFS_NAME);
+	    devfs_put (dir);
 	    return NULL;
 	}
-	/*  Ensure an unregistered entry is re-registered and visible  */
-	entry->hide = FALSE;
-	entry->registered = TRUE;
-	subname = ptr + 1;
-	dir = entry;
+	if (S_ISLNK (de->mode) && traverse_symlink)
+	{   /*  Need to follow the link: this is a stack chomper  */
+	    link = _devfs_walk_path (dir, de->u.symlink.linkname,
+				     de->u.symlink.length, TRUE);
+	    devfs_put (de);
+	    if (!link)
+	    {
+		devfs_put (dir);
+		return NULL;
+	    }
+	    de = link;
+	}
+	devfs_put (dir);
+	dir = de;
+	if (name[next_pos] == '/') ++next_pos;
     }
-    return NULL;
-}   /*  End Function search_for_entry  */
+    return dir;
+}   /*  End Function _devfs_walk_path  */
 
 
 /**
@@ -1020,20 +1194,29 @@
 {
     struct devfs_entry *entry, *de;
 
+    devfs_get (dir);
     if (dir == NULL) return NULL;
     if ( !S_ISDIR (dir->mode) )
     {
 	printk ("%s: find_by_dev(): not a directory\n", DEVFS_NAME);
+	devfs_put (dir);
 	return NULL;
     }
     /*  First search files in this directory  */
+    read_lock (&dir->u.dir.lock);
     for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
     {
 	if ( !S_ISCHR (entry->mode) && !S_ISBLK (entry->mode) ) continue;
 	if ( S_ISCHR (entry->mode) && (type != DEVFS_SPECIAL_CHR) ) continue;
 	if ( S_ISBLK (entry->mode) && (type != DEVFS_SPECIAL_BLK) ) continue;
 	if ( (entry->u.fcb.u.device.major == major) &&
-	     (entry->u.fcb.u.device.minor == minor) ) return entry;
+	     (entry->u.fcb.u.device.minor == minor) )
+	{
+	    devfs_get (entry);
+	    read_unlock (&dir->u.dir.lock);
+	    devfs_put (dir);
+	    return entry;
+	}
 	/*  Not found: try the next one  */
     }
     /*  Now recursively search the subdirectories: this is a stack chomper  */
@@ -1041,8 +1224,15 @@
     {
 	if ( !S_ISDIR (entry->mode) ) continue;
 	de = find_by_dev (entry, major, minor, type);
-	if (de) return de;
+	if (de)
+	{
+	    read_unlock (&dir->u.dir.lock);
+	    devfs_put (dir);
+	    return de;
+	}
     }
+    read_unlock (&dir->u.dir.lock);
+    devfs_put (dir);
     return NULL;
 }   /*  End Function find_by_dev  */
 
@@ -1063,7 +1253,6 @@
  *		%DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
  *	@traverse_symlink: If %TRUE then symbolic links are traversed.
  *
- *	FIXME: What the hell is @handle? - ch
  *	Returns the devfs_entry pointer on success, else %NULL.
  */
 
@@ -1095,10 +1284,7 @@
 	    ++name;
 	    --namelen;
 	}
-	if (traverse_symlink) down_read (&symlink_rwsem);
-	entry = search_for_entry (dir, name, namelen, FALSE, FALSE, NULL,
-				  traverse_symlink);
-	if (traverse_symlink) up_read (&symlink_rwsem);
+	entry = _devfs_walk_path (dir, name, namelen, traverse_symlink);
 	if (entry != NULL) return entry;
     }
     /*  Have to search by major and minor: slow  */
@@ -1106,42 +1292,34 @@
     return find_by_dev (root_entry, major, minor, type);
 }   /*  End Function find_entry  */
 
-static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode,
-							   int do_check)
+static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode)
 {
-    struct devfs_entry *de;
-
     if (inode == NULL) return NULL;
-    de = inode->u.generic_ip;
-    if (!de) printk (__FUNCTION__ "(): NULL de for inode %ld\n", inode->i_ino);
-    if (do_check && de && !de->registered) de = NULL;
-    return de;
+    return inode->u.generic_ip;
 }   /*  End Function get_devfs_entry_from_vfs_inode  */
 
 
 /**
- *	free_dentries - Free the dentries for a device entry and invalidate inodes.
+ *	free_dentry - Free the dentry for a device entry and invalidate inode.
  *	@de: The entry.
+ *
+ *	This must only be called after the entry has been unhooked from it's
+ *	 parent directory.
  */
 
-static void free_dentries (struct devfs_entry *de)
+static void free_dentry (struct devfs_entry *de)
 {
-    struct dentry *dentry;
+    struct dentry *dentry = de->inode.dentry;
 
+    if (!dentry) return;
     spin_lock (&dcache_lock);
-    dentry = de->inode.dentry;
-    if (dentry != NULL)
-    {
-	dget_locked (dentry);
-	de->inode.dentry = NULL;
-	spin_unlock (&dcache_lock);
-	/*  Forcefully remove the inode  */
-	if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
-	d_drop (dentry);
-	dput (dentry);
-    }
-    else spin_unlock (&dcache_lock);
-}   /*  End Function free_dentries  */
+    dget_locked (dentry);
+    spin_unlock (&dcache_lock);
+    /*  Forcefully remove the inode  */
+    if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
+    d_drop (dentry);
+    dput (dentry);
+}   /*  End Function free_dentry  */
 
 
 /**
@@ -1155,10 +1333,14 @@
 {
     struct task_struct *p;
 
-    for (p = current; p != &init_task; p = p->p_opptr)
+    if (current == fs_info->devfsd_task) return (TRUE);
+    if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
+    for (p = current->p_opptr; p != &init_task; p = p->p_opptr)
     {
 	if (p == fs_info->devfsd_task) return (TRUE);
     }
+#endif
     return (FALSE);
 }   /*  End Function is_devfsd_or_child  */
 
@@ -1172,7 +1354,7 @@
 
 static inline int devfsd_queue_empty (struct fs_info *fs_info)
 {
-    return (fs_info->devfsd_buf_out == fs_info->devfsd_buf_in) ? TRUE : FALSE;
+    return (fs_info->devfsd_last_event) ? FALSE : TRUE;
 }   /*  End Function devfsd_queue_empty  */
 
 
@@ -1201,8 +1383,9 @@
 
 
 /**
- *	devfsd_notify_one - Notify a single devfsd daemon of a change.
- *	@data: Data to be passed.
+ *	devfsd_notify_de - Notify the devfsd daemon of a change.
+ *	@de: The devfs entry that has changed. This and all parent entries will
+ *            have their reference counts incremented if the event was queued.
  *	@type: The type of change.
  *	@mode: The mode of the entry.
  *	@uid: The user ID.
@@ -1212,51 +1395,51 @@
  *	Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
  */
 
-static int devfsd_notify_one (void *data, unsigned int type, umode_t mode,
-			      uid_t uid, gid_t gid, struct fs_info *fs_info)
+static int devfsd_notify_de (struct devfs_entry *de,
+			     unsigned short type, umode_t mode,
+			     uid_t uid, gid_t gid, struct fs_info *fs_info,
+			     int atomic)
 {
-    unsigned int next_pos;
-    unsigned long flags;
     struct devfsd_buf_entry *entry;
+    struct devfs_entry *curr;
 
     if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE);
-    next_pos = fs_info->devfsd_buf_in + 1;
-    if (next_pos >= devfsd_buf_size) next_pos = 0;
-    if (next_pos == fs_info->devfsd_buf_out)
+    if ( ( entry = kmem_cache_alloc (devfsd_buf_cache,
+				     atomic ? SLAB_ATOMIC : SLAB_KERNEL) )
+	 == NULL )
     {
-	/*  Running up the arse of the reader: drop it  */
 	atomic_inc (&fs_info->devfsd_overrun_count);
 	return (FALSE);
     }
-    spin_lock_irqsave (&fs_info->devfsd_buffer_lock, flags);
-    next_pos = fs_info->devfsd_buf_in + 1;
-    if (next_pos >= devfsd_buf_size) next_pos = 0;
-    entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer +
-	fs_info->devfsd_buf_in;
-    entry->data = data;
+    for (curr = de; curr != NULL; curr = curr->parent) devfs_get (curr);
+    entry->de = de;
     entry->type = type;
     entry->mode = mode;
     entry->uid = uid;
     entry->gid = gid;
-    fs_info->devfsd_buf_in = next_pos;
-    spin_unlock_irqrestore (&fs_info->devfsd_buffer_lock, flags);
+    entry->next = NULL;
+    spin_lock (&fs_info->devfsd_buffer_lock);
+    if (!fs_info->devfsd_first_event) fs_info->devfsd_first_event = entry;
+    if (fs_info->devfsd_last_event) fs_info->devfsd_last_event->next = entry;
+    fs_info->devfsd_last_event = entry;
+    spin_unlock (&fs_info->devfsd_buffer_lock);
     wake_up_interruptible (&fs_info->devfsd_wait_queue);
     return (TRUE);
-}   /*  End Function devfsd_notify_one  */
+}   /*  End Function devfsd_notify_de  */
 
 
 /**
- *	devfsd_notify - Notify all devfsd daemons of a change.
+ *	devfsd_notify - Notify the devfsd daemon of a change.
  *	@de: The devfs entry that has changed.
  *	@type: The type of change event.
- *	@wait: If TRUE, the functions waits for all daemons to finish processing
+ *	@wait: If TRUE, the function waits for the daemon to finish processing
  *		the event.
  */
 
-static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait)
+static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait)
 {
-    if (devfsd_notify_one (de, type, de->mode, current->euid,
-			   current->egid, &fs_info) && wait)
+    if (devfsd_notify_de (de, type, de->mode, current->euid,
+			  current->egid, &fs_info, 0) && wait)
 	wait_for_devfsd_finished (&fs_info);
 }   /*  End Function devfsd_notify  */
 
@@ -1287,7 +1470,7 @@
 			       umode_t mode, void *ops, void *info)
 {
     char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK;
-    int is_new;
+    int err;
     kdev_t devnum = NODEV;
     struct devfs_entry *de;
 
@@ -1332,146 +1515,127 @@
 	major = MAJOR (devnum);
 	minor = MINOR (devnum);
     }
-    de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new,
-			   FALSE);
-    if (de == NULL)
+    if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
     {
-	printk ("%s: devfs_register(): could not create entry: \"%s\"\n",
+	printk ("%s: devfs_register(%s): could not prepare leaf\n",
 		DEVFS_NAME, name);
 	if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
 	return NULL;
     }
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_register(%s): de: %p %s\n",
-		DEVFS_NAME, name, de, is_new ? "new" : "existing");
-#endif
-    if (!is_new)
-    {
-	/*  Existing entry  */
-	if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) &&
-	     !S_ISREG (de->mode) )
-	{
-	    printk ("%s: devfs_register(): existing non-device/file entry: \"%s\"\n",
-		    DEVFS_NAME, name);
-	    if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
-	    return NULL;
-	}
-	if (de->registered)
-	{
-	    printk("%s: devfs_register(): device already registered: \"%s\"\n",
-		   DEVFS_NAME, name);
-	    if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
-	    return NULL;
-	}
-    }
-    de->u.fcb.autogen = FALSE;
     if ( S_ISCHR (mode) || S_ISBLK (mode) )
     {
 	de->u.fcb.u.device.major = major;
 	de->u.fcb.u.device.minor = minor;
 	de->u.fcb.autogen = (devnum == NODEV) ? FALSE : TRUE;
     }
-    else if ( S_ISREG (mode) ) de->u.fcb.u.file.size = 0;
-    else
+    else if ( !S_ISREG (mode) )
     {
-	printk ("%s: devfs_register(): illegal mode: %x\n",
-		DEVFS_NAME, mode);
+	printk ("%s: devfs_register(%s): illegal mode: %x\n",
+		DEVFS_NAME, name, mode);
+	devfs_put (de);
+	devfs_put (dir);
 	return (NULL);
     }
     de->info = info;
-    de->mode = mode;
     if (flags & DEVFS_FL_CURRENT_OWNER)
     {
-	de->u.fcb.default_uid = current->uid;
-	de->u.fcb.default_gid = current->gid;
+	de->inode.uid = current->uid;
+	de->inode.gid = current->gid;
     }
     else
     {
-	de->u.fcb.default_uid = 0;
-	de->u.fcb.default_gid = 0;
+	de->inode.uid = 0;
+	de->inode.gid = 0;
     }
     de->u.fcb.ops = ops;
     de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
     de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
-    if (flags & DEVFS_FL_REMOVABLE)
-    {
-	de->u.fcb.removable = TRUE;
-	++de->parent->u.dir.num_removable;
-    }
-    de->u.fcb.open = FALSE;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
-    de->no_persistence = (flags & DEVFS_FL_NO_PERSISTENCE) ? TRUE : FALSE;
-    de->registered = TRUE;
+    if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;
+    if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) )
+	 != 0 )
+    {
+	printk("%s: devfs_register(%s): could not append to parent, err: %d\n",
+	       DEVFS_NAME, name, err);
+	devfs_put (dir);
+	if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
+	return NULL;
+    }
+#ifdef CONFIG_DEVFS_DEBUG
+    if (devfs_debug & DEBUG_REGISTER)
+	printk ("%s: devfs_register(%s): de: %p dir: %p \"%s\"  pp: %p\n",
+		DEVFS_NAME, name, de, dir, dir->name, dir->parent);
+#endif
     devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
+    devfs_put (dir);
     return de;
 }   /*  End Function devfs_register  */
 
 
 /**
- *	unregister - Unregister a device entry.
+ *	_devfs_unhook - Unhook a device entry from its parents list
+ *	@de: The entry to unhook.
+ *
+ *	Returns %TRUE if the entry was unhooked, else %FALSE if it was
+ *		previously unhooked.
+ *	The caller must have a write lock on the parent directory.
+ */
+
+static int _devfs_unhook (struct devfs_entry *de)
+{
+    struct devfs_entry *parent;
+
+    if ( !de || (de->prev == de) ) return FALSE;
+    parent = de->parent;
+    if (de->prev == NULL) parent->u.dir.first = de->next;
+    else de->prev->next = de->next;
+    if (de->next == NULL) parent->u.dir.last = de->prev;
+    else de->next->prev = de->prev;
+    de->prev = de;          /*  Indicate we're unhooked                      */
+    de->next = NULL;        /*  Force early termination for <devfs_readdir>  */
+    if ( ( S_ISREG (de->mode) || S_ISCHR (de->mode) || S_ISBLK (de->mode) ) &&
+	 de->u.fcb.removable )
+	--parent->u.dir.num_removable;
+    return TRUE;
+}   /*  End Function _devfs_unhook  */
+
+
+/**
+ *	unregister - Unregister a device entry from it's parent.
+ *	@dir: The parent directory.
  *	@de: The entry to unregister.
+ *
+ *	The caller must have a write lock on the parent directory, which is
+ *	unlocked by this function.
  */
 
-static void unregister (struct devfs_entry *de)
+static void unregister (struct devfs_entry *dir, struct devfs_entry *de)
 {
-    struct devfs_entry *child;
+    int unhooked = _devfs_unhook (de);
 
-    if ( (child = de->slave) != NULL )
-    {
-	de->slave = NULL;  /* Unhook first in case slave is parent directory */
-	unregister (child);
-    }
-    if (de->registered)
-    {
-	devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);
-	free_dentries (de);
-    }
-    de->info = NULL;
-    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-    {
-	de->registered = FALSE;
-	de->u.fcb.ops = NULL;
-	if (!S_ISREG (de->mode) && de->u.fcb.autogen)
-	{
-	    devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
-				   DEVFS_SPECIAL_BLK,
-				   MKDEV (de->u.fcb.u.device.major,
-					  de->u.fcb.u.device.minor) );
-	}
-	de->u.fcb.autogen = FALSE;
-	return;
-    }
-    if (S_ISLNK (de->mode) && de->registered)
-    {
-	de->registered = FALSE;
-	down_write (&symlink_rwsem);
-	if (de->u.symlink.linkname) kfree (de->u.symlink.linkname);
-	de->u.symlink.linkname = NULL;
-	up_write (&symlink_rwsem);
-	return;
-    }
-    if ( S_ISFIFO (de->mode) )
-    {
-	de->registered = FALSE;
-	return;
-    }
-    if (!de->registered) return;
-    if ( !S_ISDIR (de->mode) )
-    {
-	printk ("%s: unregister(): unsupported type\n", DEVFS_NAME);
-	return;
-    }
-    de->registered = FALSE;
-    /*  Now recursively search the subdirectories: this is a stack chomper  */
-    for (child = de->u.dir.first; child != NULL; child = child->next)
-    {
+    write_unlock (&dir->u.dir.lock);
+    if (!unhooked) return;
+    devfs_get (dir);
+    devfs_unregister (de->slave);  /*  Let it handle the locking  */
+    devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);
+    free_dentry (de);
+    devfs_put (dir);
+    if ( !S_ISDIR (de->mode) ) return;
+    while (TRUE)  /*  Recursively unregister: this is a stack chomper  */
+    {
+	struct devfs_entry *child;
+
+	write_lock (&de->u.dir.lock);
+	de->u.dir.no_more_additions = TRUE;
+	child = de->u.dir.first;
+	unregister (de, child);
+	if (!child) break;
 #ifdef CONFIG_DEVFS_DEBUG
 	if (devfs_debug & DEBUG_UNREGISTER)
 	    printk ("%s: unregister(): child->name: \"%s\" child: %p\n",
 		    DEVFS_NAME, child->name, child);
 #endif
-	unregister (child);
+	devfs_put (child);
     }
 }   /*  End Function unregister  */
 
@@ -1484,20 +1648,22 @@
 
 void devfs_unregister (devfs_handle_t de)
 {
-    if (de == NULL) return;
+    if ( (de == NULL) || (de->parent == NULL) ) return;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_UNREGISTER)
 	printk ("%s: devfs_unregister(): de->name: \"%s\" de: %p\n",
 		DEVFS_NAME, de->name, de);
 #endif
-    unregister (de);
+    write_lock (&de->parent->u.dir.lock);
+    unregister (de->parent, de);
+    devfs_put (de);
 }   /*  End Function devfs_unregister  */
 
 static int devfs_do_symlink (devfs_handle_t dir, const char *name,
 			     unsigned int flags, const char *link,
 			     devfs_handle_t *handle, void *info)
 {
-    int is_new;
+    int err;
     unsigned int linklength;
     char *newlink;
     struct devfs_entry *de;
@@ -1522,28 +1688,31 @@
 	return -ENOMEM;
     memcpy (newlink, link, linklength);
     newlink[linklength] = '\0';
-    if ( ( de = search_for_entry (dir, name, strlen (name), TRUE, TRUE,
-				  &is_new, FALSE) ) == NULL )
+    if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) )
+	 == NULL )
     {
-	kfree (newlink);
-	return -ENOMEM;
-    }
-    down_write (&symlink_rwsem);
-    if (de->registered)
-    {
-	up_write (&symlink_rwsem);
-	kfree (newlink);
-	printk ("%s: devfs_do_symlink(%s): entry already exists\n",
+	printk ("%s: devfs_do_symlink(%s): could not prepare leaf\n",
 		DEVFS_NAME, name);
-	return -EEXIST;
+	kfree (newlink);
+	return -ENOTDIR;
     }
-    de->mode = S_IFLNK | S_IRUGO | S_IXUGO;
     de->info = info;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
     de->u.symlink.linkname = newlink;
     de->u.symlink.length = linklength;
-    de->registered = TRUE;
-    up_write (&symlink_rwsem);
+    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
+    {
+	printk ("%s: devfs_do_symlink(%s): could not append to parent, err: %d\n",
+		DEVFS_NAME, name, err);
+	devfs_put (dir);
+	return err;
+    }
+    devfs_put (dir);
+#ifdef CONFIG_DEVFS_DEBUG
+    spin_lock (&stat_lock);
+    stat_num_bytes += linklength + 1;
+    spin_unlock (&stat_lock);
+#endif
     if (handle != NULL) *handle = de;
     return 0;
 }   /*  End Function devfs_do_symlink  */
@@ -1593,7 +1762,7 @@
 
 devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
 {
-    int is_new;
+    int err;
     struct devfs_entry *de;
 
     if (name == NULL)
@@ -1601,36 +1770,27 @@
 	printk ("%s: devfs_mk_dir(): NULL name pointer\n", DEVFS_NAME);
 	return NULL;
     }
-    de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new,
-			   FALSE);
-    if (de == NULL)
+    if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL )
     {
-	printk ("%s: devfs_mk_dir(): could not create entry: \"%s\"\n",
+	printk ("%s: devfs_mk_dir(%s): could not prepare leaf\n",
 		DEVFS_NAME, name);
 	return NULL;
     }
-    if (!S_ISDIR (de->mode) && de->registered)
+    de->info = info;
+    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
     {
-	printk ("%s: devfs_mk_dir(): existing non-directory entry: \"%s\"\n",
-		DEVFS_NAME, name);
+	printk ("%s: devfs_mk_dir(%s): could not append to dir: %p \"%s\", err: %d\n",
+		DEVFS_NAME, name, dir, dir->name, err);
+	devfs_put (dir);
 	return NULL;
     }
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_mk_dir(%s): de: %p %s\n",
-		DEVFS_NAME, name, de, is_new ? "new" : "existing");
+	printk ("%s: devfs_mk_dir(%s): de: %p dir: %p \"%s\"\n",
+		DEVFS_NAME, name, de, dir, dir->name);
 #endif
-    if (!S_ISDIR (de->mode) && !is_new)
-    {
-	/*  Transmogrifying an old entry  */
-	de->u.dir.first = NULL;
-	de->u.dir.last = NULL;
-    }
-    de->mode = S_IFDIR | S_IRUGO | S_IXUGO;
-    de->info = info;
-    if (!de->registered) de->u.dir.num_removable = 0;
-    de->hide = FALSE;
-    de->registered = TRUE;
+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0);
+    devfs_put (dir);
     return de;
 }   /*  End Function devfs_mk_dir  */
 
@@ -1660,8 +1820,8 @@
 
     if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
     de = find_entry (dir, name, 0, major, minor, type, traverse_symlinks);
-    if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
+    devfs_put (de);  /*  FIXME: in 2.5 consider dropping this and require a
+			 call to devfs_put()  */
     return de;
 }   /*  End Function devfs_find_handle  */
 
@@ -1679,7 +1839,6 @@
     unsigned int fl = 0;
 
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -ENODEV;
     if (de->hide) fl |= DEVFS_FL_HIDE;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
     {
@@ -1703,7 +1862,6 @@
 int devfs_set_flags (devfs_handle_t de, unsigned int flags)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -ENODEV;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_SET_FLAGS)
 	printk ("%s: devfs_set_flags(): de->name: \"%s\"\n",
@@ -1714,16 +1872,6 @@
     {
 	de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
 	de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE:FALSE;
-	if ( de->u.fcb.removable && !(flags & DEVFS_FL_REMOVABLE) )
-	{
-	    de->u.fcb.removable = FALSE;
-	    --de->parent->u.dir.num_removable;
-	}
-	else if ( !de->u.fcb.removable && (flags & DEVFS_FL_REMOVABLE) )
-	{
-	    de->u.fcb.removable = TRUE;
-	    ++de->parent->u.dir.num_removable;
-	}
     }
     return 0;
 }   /*  End Function devfs_set_flags  */
@@ -1742,7 +1890,6 @@
 		       unsigned int *minor)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -ENODEV;
     if ( S_ISDIR (de->mode) ) return -EISDIR;
     if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) ) return -EINVAL;
     if (major != NULL) *major = de->u.fcb.u.device.major;
@@ -1762,7 +1909,7 @@
 {
     if (!inode || !inode->i_sb) return NULL;
     if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL;
-    return get_devfs_entry_from_vfs_inode (inode, TRUE);
+    return get_devfs_entry_from_vfs_inode (inode);
 }   /*  End Function devfs_get_handle_from_inode  */
 
 
@@ -1780,19 +1927,20 @@
 int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
 {
     int pos;
+#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
 
     if (de == NULL) return -EINVAL;
     if (de->namelen >= buflen) return -ENAMETOOLONG; /*  Must be first       */
     path[buflen - 1] = '\0';
     if (de->parent == NULL) return buflen - 1;       /*  Don't prepend root  */
     pos = buflen - de->namelen - 1;
-    memcpy (path + pos, de->name, de->namelen);
+    memcpy (path + pos, NAMEOF (de), de->namelen);
     for (de = de->parent; de->parent != NULL; de = de->parent)
     {
 	if (pos - de->namelen - 1 < 0) return -ENAMETOOLONG;
 	path[--pos] = '/';
 	pos -= de->namelen;
-	memcpy (path + pos, de->name, de->namelen);
+	memcpy (path + pos, NAMEOF (de), de->namelen);
     }
     return pos;
 }   /*  End Function devfs_generate_path  */
@@ -1808,7 +1956,6 @@
 void *devfs_get_ops (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
 	return de->u.fcb.ops;
     return NULL;
@@ -1826,7 +1973,6 @@
 int devfs_set_file_size (devfs_handle_t de, unsigned long size)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -EINVAL;
     if ( !S_ISREG (de->mode) ) return -EINVAL;
     if (de->u.fcb.u.file.size == size) return 0;
     de->u.fcb.u.file.size = size;
@@ -1846,7 +1992,6 @@
 void *devfs_get_info (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     return de->info;
 }   /*  End Function devfs_get_info  */
 
@@ -1861,7 +2006,6 @@
 int devfs_set_info (devfs_handle_t de, void *info)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -EINVAL;
     de->info = info;
     return 0;
 }   /*  End Function devfs_set_info  */
@@ -1876,7 +2020,6 @@
 devfs_handle_t devfs_get_parent (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     return de->parent;
 }   /*  End Function devfs_get_parent  */
 
@@ -1891,7 +2034,6 @@
 devfs_handle_t devfs_get_first_child (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     if ( !S_ISDIR (de->mode) ) return NULL;
     return de->u.dir.first;
 }   /*  End Function devfs_get_first_child  */
@@ -1907,7 +2049,6 @@
 devfs_handle_t devfs_get_next_sibling (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     return de->next;
 }   /*  End Function devfs_get_next_sibling  */
 
@@ -1961,7 +2102,6 @@
 const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     if (namelen != NULL) *namelen = de->namelen;
     return de->name;
 }   /*  End Function devfs_get_name  */
@@ -2057,8 +2197,10 @@
 	{"dmod",      DEBUG_MODULE_LOAD,  &devfs_debug_init},
 	{"dreg",      DEBUG_REGISTER,     &devfs_debug_init},
 	{"dunreg",    DEBUG_UNREGISTER,   &devfs_debug_init},
+	{"dfree",     DEBUG_FREE,         &devfs_debug_init},
 	{"diget",     DEBUG_I_GET,        &devfs_debug_init},
 	{"dchange",   DEBUG_SET_FLAGS,    &devfs_debug_init},
+	{"dsread",    DEBUG_S_READ,       &devfs_debug_init},
 	{"dichange",  DEBUG_I_CHANGE,     &devfs_debug_init},
 	{"dimknod",   DEBUG_I_MKNOD,      &devfs_debug_init},
 	{"dilookup",  DEBUG_I_LOOKUP,     &devfs_debug_init},
@@ -2129,34 +2271,31 @@
 
 
 /**
- *	try_modload - Notify devfsd of an inode lookup.
+ *	try_modload - Notify devfsd of an inode lookup by a non-devfsd process.
  *	@parent: The parent devfs entry.
  *	@fs_info: The filesystem info.
  *	@name: The device name.
  *	@namelen: The number of characters in @name.
- *	@buf: A working area that will be used. This must not go out of scope until
- *		devfsd is idle again.
+ *	@buf: A working area that will be used. This must not go out of scope
+ *            until devfsd is idle again.
  *
  *	Returns 0 on success, else a negative error code.
  */
 
 static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
 			const char *name, unsigned namelen,
-			char buf[STRING_LENGTH])
+			struct devfs_entry *buf)
 {
-    int pos = STRING_LENGTH - namelen - 1;
-
     if ( !( fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP) ) )
 	return -ENOENT;
     if ( is_devfsd_or_child (fs_info) ) return -ENOENT;
-    if (namelen >= STRING_LENGTH - 1) return -ENAMETOOLONG;
-    memcpy (buf + pos, name, namelen);
-    buf[STRING_LENGTH - 1] = '\0';
-    if (parent->parent != NULL) pos = devfs_generate_path (parent, buf, pos);
-    if (pos < 0) return pos;
-    buf[STRING_LENGTH - namelen - 2] = '/';
-    if ( !devfsd_notify_one (buf + pos, DEVFSD_NOTIFY_LOOKUP, 0,
-			     current->euid, current->egid, fs_info) )
+    memset (buf, 0, sizeof *buf);
+    atomic_set (&buf->refcount, 1);
+    buf->parent = parent;
+    buf->namelen = namelen;
+    buf->u.name = name;
+    if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
+			    current->euid, current->egid, fs_info, 0) )
 	return -ENOENT;
     /*  Possible success  */
     return 0;
@@ -2206,7 +2345,6 @@
     if (dir->u.dir.num_removable < 1) return;
     for (de = dir->u.dir.first; de != NULL; de = de->next)
     {
-	if (!de->registered) continue;
 	if ( !S_ISBLK (de->mode) ) continue;
 	if (!de->u.fcb.removable) continue;
 	check_disc_changed (de);
@@ -2229,7 +2367,6 @@
 
     for (de = dir->u.dir.first; de != NULL; de = de->next)
     {
-	if (!de->registered) continue;
 	if ( !S_ISBLK (de->mode) ) continue;
 	if (!de->u.fcb.removable) continue;
 	if (strcmp (de->name, "disc") == 0) return check_disc_changed (de);
@@ -2258,7 +2395,7 @@
     struct inode *inode = dentry->d_inode;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENODEV;
     retval = inode_change_ok (inode, iattr);
     if (retval != 0) return retval;
@@ -2276,15 +2413,20 @@
 #endif
     /*  Inode is not on hash chains, thus must save permissions here rather
 	than in a write_inode() method  */
-    de->inode.mode = inode->i_mode;
-    de->inode.uid = inode->i_uid;
-    de->inode.gid = inode->i_gid;
+    if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) &&
+	   !S_ISBLK (inode->i_mode) ) || !de->u.fcb.auto_owner )
+    {
+	de->mode = inode->i_mode;
+	de->inode.uid = inode->i_uid;
+	de->inode.gid = inode->i_gid;
+    }
     de->inode.atime = inode->i_atime;
     de->inode.mtime = inode->i_mtime;
     de->inode.ctime = inode->i_ctime;
-    if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) )
-	devfsd_notify_one (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
-			   inode->i_uid, inode->i_gid, fs_info);
+    if ( ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) &&
+	 !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info, 0);
     return 0;
 }   /*  End Function devfs_notify_change  */
 
@@ -2299,11 +2441,10 @@
     return 0;
 }   /*  End Function devfs_statfs  */
 
-static void devfs_clear_inode(struct inode *inode)
+static void devfs_clear_inode (struct inode *inode)
 {
-	if (S_ISBLK(inode->i_mode))
-		bdput(inode->i_bdev);
-}
+    if ( S_ISBLK (inode->i_mode) ) bdput (inode->i_bdev);
+}   /*  End Function devfs_clear_inode  */
 
 static struct super_operations devfs_sops =
 { 
@@ -2319,32 +2460,37 @@
  *	@de: The devfs inode.
  *	@dentry: The dentry to register with the devfs inode.
  *
- *	Returns the inode on success, else %NULL.
+ *	Returns the inode on success, else %NULL. An implicit devfs_get() is
+ *       performed if the inode is created.
  */
 
 static struct inode *get_vfs_inode (struct super_block *sb,
 				    struct devfs_entry *de,
 				    struct dentry *dentry)
 {
+    int is_fcb = FALSE;
     struct inode *inode;
 
-    if (de->inode.dentry != NULL)
-    {
-	printk ("%s: get_vfs_inode(%u): old de->inode.dentry: %p \"%s\"  new dentry: %p \"%s\"\n",
-		DEVFS_NAME, de->inode.ino,
-		de->inode.dentry, de->inode.dentry->d_name.name,
-		dentry, dentry->d_name.name);
-	printk ("  old inode: %p\n", de->inode.dentry->d_inode);
-	return NULL;
-    }
+    if (de->prev == de) return NULL;  /*  Quick check to see if unhooked  */
     if ( ( inode = new_inode (sb) ) == NULL )
     {
 	printk ("%s: get_vfs_inode(%s): new_inode() failed, de: %p\n",
 		DEVFS_NAME, de->name, de);
 	return NULL;
     }
-    de->inode.dentry = dentry;
-    inode->u.generic_ip = de;
+    if (de->parent)
+    {
+	read_lock (&de->parent->u.dir.lock);
+	if (de->prev != de) de->inode.dentry = dentry; /*      Not unhooked  */
+	read_unlock (&de->parent->u.dir.lock);
+    }
+    else de->inode.dentry = dentry;             /*  Root: no locking needed  */
+    if (de->inode.dentry != dentry)
+    {   /*  Must have been unhooked  */
+	iput (inode);
+	return NULL;
+    }
+    inode->u.generic_ip = devfs_get (de);
     inode->i_ino = de->inode.ino;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_GET)
@@ -2356,37 +2502,45 @@
     inode->i_op = &devfs_iops;
     inode->i_fop = &devfs_fops;
     inode->i_rdev = NODEV;
-    if ( S_ISCHR (de->inode.mode) )
+    if ( S_ISCHR (de->mode) )
     {
 	inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
 			       de->u.fcb.u.device.minor);
-	inode->i_cdev = cdget (kdev_t_to_nr(inode->i_rdev));
+	inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
+	is_fcb = TRUE;
     }
-    else if ( S_ISBLK (de->inode.mode) )
+    else if ( S_ISBLK (de->mode) )
     {
 	inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
 			       de->u.fcb.u.device.minor);
-	if (bd_acquire(inode) == 0)
+	if (bd_acquire (inode) == 0)
 	{
 	    if (!inode->i_bdev->bd_op && de->u.fcb.ops)
 		inode->i_bdev->bd_op = de->u.fcb.ops;
 	}
 	else printk ("%s: get_vfs_inode(%d): no block device from bdget()\n",
 		     DEVFS_NAME, (int) inode->i_ino);
+	is_fcb = TRUE;
     }
-    else if ( S_ISFIFO (de->inode.mode) ) inode->i_fop = &def_fifo_fops;
-    else if ( S_ISREG (de->inode.mode) ) inode->i_size = de->u.fcb.u.file.size;
-    else if ( S_ISDIR (de->inode.mode) )
+    else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops;
+    else if ( S_ISREG (de->mode) )
+    {
+	inode->i_size = de->u.fcb.u.file.size;
+	is_fcb = TRUE;
+    }
+    else if ( S_ISDIR (de->mode) )
     {
 	inode->i_op = &devfs_dir_iops;
     	inode->i_fop = &devfs_dir_fops;
     }
-    else if ( S_ISLNK (de->inode.mode) )
+    else if ( S_ISLNK (de->mode) )
     {
 	inode->i_op = &devfs_symlink_iops;
 	inode->i_size = de->u.symlink.length;
     }
-    inode->i_mode = de->inode.mode;
+    if (is_fcb && de->u.fcb.auto_owner)
+	inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
+    else inode->i_mode = de->mode;
     inode->i_uid = de->inode.uid;
     inode->i_gid = de->inode.gid;
     inode->i_atime = de->inode.atime;
@@ -2409,11 +2563,11 @@
     int err, count;
     int stored = 0;
     struct fs_info *fs_info;
-    struct devfs_entry *parent, *de;
+    struct devfs_entry *parent, *de, *next = NULL;
     struct inode *inode = file->f_dentry->d_inode;
 
     fs_info = inode->i_sb->u.generic_sbp;
-    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode);
     if ( (long) file->f_pos < 0 ) return -EINVAL;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_F_READDIR)
@@ -2441,19 +2595,32 @@
       default:
 	/*  Skip entries  */
 	count = file->f_pos - 2;
-	for (de = parent->u.dir.first; (de != NULL) && (count > 0);
-	     de = de->next)
+	read_lock (&parent->u.dir.lock);
+	for (de = parent->u.dir.first; de && (count > 0); de = de->next)
 	    if ( !IS_HIDDEN (de) ) --count;
+	devfs_get (de);
+	read_unlock (&parent->u.dir.lock);
 	/*  Now add all remaining entries  */
-	for (; de != NULL; de = de->next)
+	while (de)
 	{
-	    if ( IS_HIDDEN (de) ) continue;
-	    err = (*filldir) (dirent, de->name, de->namelen,
-			      file->f_pos, de->inode.ino, de->mode >> 12);
+	    if ( IS_HIDDEN (de) ) err = 0;
+	    else
+	    {
+		err = (*filldir) (dirent, de->name, de->namelen,
+				  file->f_pos, de->inode.ino, de->mode >> 12);
+		if (err >= 0)
+		{
+		    file->f_pos++;
+		    ++stored;
+		}
+	    }
+	    read_lock (&parent->u.dir.lock);
+	    next = devfs_get (de->next);
+	    read_unlock (&parent->u.dir.lock);
+	    devfs_put (de);
+	    de = next;
 	    if (err == -EINVAL) break;
 	    if (err < 0) return err;
-	    file->f_pos++;
-	    ++stored;
 	}
 	break;
     }
@@ -2467,14 +2634,9 @@
     struct devfs_entry *de;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
-    err = -ENODEV;
-    if (de == NULL)
-	goto out;
-    err = 0;
-    if ( S_ISDIR (de->mode) )
-	goto out;
+    de = get_devfs_entry_from_vfs_inode (inode);
+    if (de == NULL) return -ENODEV;
+    if ( S_ISDIR (de->mode) ) return 0;
     df = &de->u.fcb;
     file->private_data = de->info;
     if ( S_ISBLK (inode->i_mode) )
@@ -2482,7 +2644,7 @@
 	file->f_op = &def_blk_fops;
 	if (df->ops) inode->i_bdev->bd_op = df->ops;
     }
-    else file->f_op = fops_get ( (struct file_operations*) df->ops );
+    else file->f_op = fops_get ( (struct file_operations *) df->ops );
     if (file->f_op)
 	err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
     else
@@ -2491,39 +2653,33 @@
 	if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
 	else err = -ENODEV;
     }
-    if (err < 0) goto out;
+    if (err < 0) return err;
     /*  Open was successful  */
-    err = 0;
-    if (df->open) goto out;
+    if (df->open) return 0;
     df->open = TRUE;  /*  This is the first open  */
     if (df->auto_owner)
     {
-	/*  Change the ownership/protection  */
-	de->inode.mode = (de->inode.mode & ~S_IALLUGO) |(de->mode & S_IRWXUGO);
-	de->inode.uid = current->euid;
-	de->inode.gid = current->egid;
-	inode->i_mode = de->inode.mode;
-	inode->i_uid = de->inode.uid;
-	inode->i_gid = de->inode.gid;
-    }
-    if (df->aopen_notify)
-	devfsd_notify_one (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
-			   current->euid, current->egid, fs_info);
-out:
-    unlock_kernel ();
-    return err;
+	/*  Change the ownership/protection to what driver specified  */
+	inode->i_mode = de->mode;
+	inode->i_uid = current->euid;
+	inode->i_gid = current->egid;
+    }
+    if ( df->aopen_notify && !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
+			  current->euid, current->egid, fs_info, 0);
+    return 0;
 }   /*  End Function devfs_open  */
 
 static struct file_operations devfs_fops =
 {
-    open: devfs_open,
+    open:    devfs_open,
 };
 
 static struct file_operations devfs_dir_fops =
 {
-    read: generic_read_dir,
+    read:    generic_read_dir,
     readdir: devfs_readdir,
-    open: devfs_open,
+    open:    devfs_open,
 };
 
 
@@ -2556,16 +2712,18 @@
 {
     struct devfs_entry *de;
 
-    lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (inode, FALSE);
+    de = get_devfs_entry_from_vfs_inode (inode);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_D_IPUT)
 	printk ("%s: d_iput(): dentry: %p inode: %p de: %p  de->dentry: %p\n",
 		DEVFS_NAME, dentry, inode, de, de->inode.dentry);
 #endif
-    if (de->inode.dentry == dentry) de->inode.dentry = NULL;
-    unlock_kernel ();
+    if ( de->inode.dentry && (de->inode.dentry != dentry) )
+	OOPS ("%s: d_iput(%s): de: %p dentry: %p de->dentry: %p\n",
+	      DEVFS_NAME, de->name, de, dentry, de->inode.dentry);
+    de->inode.dentry = NULL;
     iput (inode);
+    devfs_put (de);
 }   /*  End Function devfs_d_iput  */
 
 static int devfs_d_delete (struct dentry *dentry);
@@ -2610,7 +2768,7 @@
 	return 1;
     }
     fs_info = inode->i_sb->u.generic_sbp;
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_D_DELETE)
 	printk ("%s: d_delete(): dentry: %p  inode: %p  devfs_entry: %p\n",
@@ -2622,14 +2780,11 @@
     if (!de->u.fcb.open) return 0;
     de->u.fcb.open = FALSE;
     if (de->u.fcb.aopen_notify)
-	devfsd_notify_one (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
-			   current->euid, current->egid, fs_info);
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
+			  current->euid, current->egid, fs_info, 1);
     if (!de->u.fcb.auto_owner) return 0;
     /*  Change the ownership/protection back  */
-    de->inode.mode = (de->inode.mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
-    de->inode.uid = de->u.fcb.default_uid;
-    de->inode.gid = de->u.fcb.default_gid;
-    inode->i_mode = de->inode.mode;
+    inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
     inode->i_uid = de->inode.uid;
     inode->i_gid = de->inode.gid;
     return 0;
@@ -2637,59 +2792,38 @@
 
 static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
 {
-    devfs_handle_t de = dentry->d_fsdata;
-    struct inode *dir;
-    struct fs_info *fs_info;
+    struct inode *dir = dentry->d_parent->d_inode;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
 
-    lock_kernel ();
-    dir = dentry->d_parent->d_inode;
-    fs_info = dir->i_sb->u.generic_sbp;
-    if (!de || de->registered)
+    if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
     {
-	if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
-	{
-	    struct inode *inode;
-
-#ifdef CONFIG_DEVFS_DEBUG
-	    char txt[STRING_LENGTH];
-
-	    memset (txt, 0, STRING_LENGTH);
-	    memcpy (txt, dentry->d_name.name,
-		    (dentry->d_name.len >= STRING_LENGTH) ?
-		    (STRING_LENGTH - 1) : dentry->d_name.len);
-	    if (devfs_debug & DEBUG_I_LOOKUP)
-		printk ("%s: d_revalidate(): dentry: %p name: \"%s\" by: \"%s\"\n",
-			DEVFS_NAME, dentry, txt, current->comm);
-#endif
-	    if (de == NULL)
-	    {
-		devfs_handle_t parent;
-
-		parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
-		de = search_for_entry_in_dir (parent, dentry->d_name.name,
-					      dentry->d_name.len, FALSE);
-	    }
-	    if (de == NULL) goto out;
-	    /*  Create an inode, now that the driver information is available
-	     */
-	    if (de->no_persistence) update_devfs_inode_from_entry (de);
-	    else if (de->inode.ctime == 0) update_devfs_inode_from_entry (de);
-	    else de->inode.mode =
-		     (de->mode & ~S_IALLUGO) | (de->inode.mode & S_IALLUGO);
-	    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-		goto out;
-#ifdef CONFIG_DEVFS_DEBUG
-	    if (devfs_debug & DEBUG_I_LOOKUP)
-		printk ("%s: d_revalidate(): new VFS inode(%u): %p  devfs_entry: %p\n",
-			DEVFS_NAME, de->inode.ino, inode, de);
+	devfs_handle_t de;
+	devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+	struct inode *inode;
+
+#ifdef CONFIG_DEVFS_DEBUG
+	if (devfs_debug & DEBUG_I_LOOKUP)
+	    printk ("%s: d_revalidate(%s): dentry: %p by: \"%s\"\n",
+		    DEVFS_NAME, dentry->d_name.name, dentry, current->comm);
+#endif
+	read_lock (&parent->u.dir.lock);
+	de = _devfs_search_dir (parent, dentry->d_name.name,
+				dentry->d_name.len);
+	read_unlock (&parent->u.dir.lock);
+	if (de == NULL) return 1;
+	/*  Create an inode, now that the driver information is available  */
+	inode = get_vfs_inode (dir->i_sb, de, dentry);
+	devfs_put (de);
+	if (!inode) return 1;
+#ifdef CONFIG_DEVFS_DEBUG
+	if (devfs_debug & DEBUG_I_LOOKUP)
+	    printk ("%s: d_revalidate(): new VFS inode(%u): %p  devfs_entry: %p\n",
+		    DEVFS_NAME, de->inode.ino, inode, de);
 #endif
-	    d_instantiate (dentry, inode);
-	    goto out;
-	}
+	d_instantiate (dentry, inode);
+	return 1;
     }
     if ( wait_for_devfsd_finished (fs_info) ) dentry->d_op = &devfs_dops;
-out:
-    unlock_kernel ();
     return 1;
 }   /*  End Function devfs_d_revalidate_wait  */
 
@@ -2698,70 +2832,63 @@
 
 static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
 {
-    struct fs_info *fs_info;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
-    char txt[STRING_LENGTH];
 
     /*  Set up the dentry operations before anything else, to ensure cleaning
 	up on any error  */
     dentry->d_op = &devfs_dops;
-    memset (txt, 0, STRING_LENGTH);
-    memcpy (txt, dentry->d_name.name,
-	    (dentry->d_name.len >= STRING_LENGTH) ?
-	    (STRING_LENGTH - 1) : dentry->d_name.len);
-    fs_info = dir->i_sb->u.generic_sbp;
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (dir);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_LOOKUP)
 	printk ("%s: lookup(%s): dentry: %p parent: %p by: \"%s\"\n",
-		DEVFS_NAME, txt, dentry, parent, current->comm);
+		DEVFS_NAME, dentry->d_name.name, dentry, parent,current->comm);
 #endif
     if (parent == NULL) return ERR_PTR (-ENOENT);
-    /*  Try to reclaim an existing devfs entry  */
-    de = search_for_entry_in_dir (parent,
-				  dentry->d_name.name, dentry->d_name.len,
-				  FALSE);
-    if ( ( (de == NULL) || !de->registered ) &&
-	 (parent->u.dir.num_removable > 0) &&
+    read_lock (&parent->u.dir.lock);
+    de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
+    read_unlock (&parent->u.dir.lock);
+    if ( (de == NULL) && (parent->u.dir.num_removable > 0) &&
 	 get_removable_partition (parent, dentry->d_name.name,
 				  dentry->d_name.len) )
     {
-	if (de == NULL)
-	    de = search_for_entry_in_dir (parent, dentry->d_name.name,
-					  dentry->d_name.len, FALSE);
+	read_lock (&parent->u.dir.lock);
+	de = _devfs_search_dir (parent, dentry->d_name.name,
+				dentry->d_name.len);
+	read_unlock (&parent->u.dir.lock);
     }
-    if ( (de == NULL) || !de->registered )
-    {
-	/*  Try with devfsd. For any kind of failure, leave a negative dentry
+    if (de == NULL)
+    {   /*  Try with devfsd. For any kind of failure, leave a negative dentry
 	    so someone else can deal with it (in the case where the sysadmin
 	    does a mknod()). It's important to do this before hashing the
 	    dentry, so that the devfsd queue is filled before revalidates
 	    can start  */
+	struct devfs_entry tmp;
+
 	if (try_modload (parent, fs_info,
-			 dentry->d_name.name, dentry->d_name.len, txt) < 0)
+			 dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
 	{
 	    d_add (dentry, NULL);
 	    return NULL;
 	}
 	/*  devfsd claimed success  */
 	dentry->d_op = &devfs_wait_dops;
-	dentry->d_fsdata = de;
 	d_add (dentry, NULL);  /*  Open the floodgates  */
 	/*  Unlock directory semaphore, which will release any waiters. They
 	    will get the hashed dentry, and may be forced to wait for
 	    revalidation  */
 	up (&dir->i_sem);
-	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too  */
+	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too   */
 	down (&dir->i_sem);      /*  Grab it again because them's the rules  */
 	/*  If someone else has been so kind as to make the inode, we go home
 	    early  */
 	if (dentry->d_inode) return NULL;
-	if (de && !de->registered) return NULL;
-	if (de == NULL)
-	    de = search_for_entry_in_dir (parent, dentry->d_name.name,
-					  dentry->d_name.len, FALSE);
+	read_lock (&parent->u.dir.lock);
+	de = _devfs_search_dir (parent, dentry->d_name.name,
+				dentry->d_name.len);
+	read_unlock (&parent->u.dir.lock);
 	if (de == NULL) return NULL;
 	/*  OK, there's an entry now, but no VFS inode yet  */
     }
@@ -2771,58 +2898,49 @@
 	d_add (dentry, NULL);  /*  Open the floodgates  */
     }
     /*  Create an inode, now that the driver information is available  */
-    if (de->no_persistence) update_devfs_inode_from_entry (de);
-    else if (de->inode.ctime == 0) update_devfs_inode_from_entry (de);
-    else de->inode.mode =
-	     (de->mode & ~S_IALLUGO) | (de->inode.mode & S_IALLUGO);
-    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-	return ERR_PTR (-ENOMEM);
+    inode = get_vfs_inode (dir->i_sb, de, dentry);
+    devfs_put (de);
+    if (!inode) return ERR_PTR (-ENOMEM);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_LOOKUP)
 	printk ("%s: lookup(): new VFS inode(%u): %p  devfs_entry: %p\n",
 		DEVFS_NAME, de->inode.ino, inode, de);
 #endif
     d_instantiate (dentry, inode);
-    /*  Unlock directory semaphore, which will release any waiters. They will
-	get the hashed dentry, and may be forced to wait for revalidation  */
-    up (&dir->i_sem);
     if (dentry->d_op == &devfs_wait_dops)
-	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too  */
-    down (&dir->i_sem);          /*  Grab it again because them's the rules  */
+    {   /*  Unlock directory semaphore, which will release any waiters. They
+	    will get the hashed dentry, and may be forced to wait for
+	    revalidation  */
+	up (&dir->i_sem);
+	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too   */
+	down (&dir->i_sem);      /*  Grab it again because them's the rules  */
+    }
     return NULL;
 }   /*  End Function devfs_lookup  */
 
 static int devfs_unlink (struct inode *dir, struct dentry *dentry)
 {
+    int unhooked;
     struct devfs_entry *de;
     struct inode *inode = dentry->d_inode;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
 
 #ifdef CONFIG_DEVFS_DEBUG
-    char txt[STRING_LENGTH];
-
     if (devfs_debug & DEBUG_I_UNLINK)
-    {
-	memset (txt, 0, STRING_LENGTH);
-	memcpy (txt, dentry->d_name.name, dentry->d_name.len);
-	txt[STRING_LENGTH - 1] = '\0';
-	printk ("%s: unlink(%s)\n", DEVFS_NAME, txt);
-    }
+	printk ("%s: unlink(%s)\n", DEVFS_NAME, dentry->d_name.name);
 #endif
-
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
-    devfsd_notify_one (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, dir->i_sb->u.generic_sbp);
-    de->registered = FALSE;
-    de->hide = TRUE;
-    if ( S_ISLNK (de->mode) )
-    {
-	down_write (&symlink_rwsem);
-	if (de->u.symlink.linkname) kfree (de->u.symlink.linkname);
-	de->u.symlink.linkname = NULL;
-	up_write (&symlink_rwsem);
-    }
-    free_dentries (de);
+    if (!de->vfs_created) return -EPERM;
+    write_lock (&de->parent->u.dir.lock);
+    unhooked = _devfs_unhook (de);
+    write_unlock (&de->parent->u.dir.lock);
+    if (!unhooked) return -ENOENT;
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info, 0);
+    free_dentry (de);
+    devfs_put (de);
     return 0;
 }   /*  End Function devfs_unlink  */
 
@@ -2830,13 +2948,12 @@
 			  const char *symname)
 {
     int err;
-    struct fs_info *fs_info;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
-    fs_info = dir->i_sb->u.generic_sbp;
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
     err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
 			    symname, &de, NULL);
@@ -2846,7 +2963,9 @@
 		DEVFS_NAME, err);
 #endif
     if (err < 0) return err;
-    de->inode.mode = de->mode;
+    de->vfs_created = TRUE;
+    de->inode.uid = current->euid;
+    de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
@@ -2857,50 +2976,33 @@
 	printk ("%s: symlink(): new VFS inode(%u): %p  dentry: %p\n",
 		DEVFS_NAME, de->inode.ino, inode, dentry);
 #endif
-    de->hide = FALSE;
     d_instantiate (dentry, inode);
-    devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info, 0);
     return 0;
 }   /*  End Function devfs_symlink  */
 
 static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
-    int is_new;
-    struct fs_info *fs_info;
+    int err;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
-    mode = (mode & ~S_IFMT) | S_IFDIR;
-    fs_info = dir->i_sb->u.generic_sbp;
-    /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    mode = (mode & ~S_IFMT) | S_IFDIR;  /*  VFS doesn't pass S_IFMT part  */
+    parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
-    /*  Try to reclaim an existing devfs entry, create if there isn't one  */
-    de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
-			   FALSE, TRUE, &is_new, FALSE);
-    if (de == NULL) return -ENOMEM;
-    if (de->registered)
-    {
-	printk ("%s: mkdir(): existing entry\n", DEVFS_NAME);
-	return -EEXIST;
-    }
-    de->hide = FALSE;
-    if (!S_ISDIR (de->mode) && !is_new)
-    {
-	/*  Transmogrifying an old entry  */
-	de->u.dir.first = NULL;
-	de->u.dir.last = NULL;
-    }
-    de->mode = mode;
-    de->u.dir.num_removable = 0;
-    de->inode.mode = mode;
+    de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
+    if (!de) return -ENOMEM;
+    de->vfs_created = TRUE;
+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
+	return err;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    de->registered = TRUE;
     if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
 #ifdef CONFIG_DEVFS_DEBUG
@@ -2909,100 +3011,73 @@
 		DEVFS_NAME, de->inode.ino, inode, dentry);
 #endif
     d_instantiate (dentry, inode);
-    devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info, 0);
     return 0;
 }   /*  End Function devfs_mkdir  */
 
 static int devfs_rmdir (struct inode *dir, struct dentry *dentry)
 {
-    int has_children = FALSE;
-    struct fs_info *fs_info;
-    struct devfs_entry *de, *child;
+    int err = 0;
+    struct devfs_entry *de;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct inode *inode = dentry->d_inode;
 
     if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
-    fs_info = dir->i_sb->u.generic_sbp;
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
-    for (child = de->u.dir.first; child != NULL; child = child->next)
-    {
-	if (child->registered)
-	{
-	    has_children = TRUE;
-	    break;
-	}
-    }
-    if (has_children) return -ENOTEMPTY;
-    devfsd_notify_one (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
-    de->hide = TRUE;
-    de->registered = FALSE;
-    free_dentries (de);
+    if (!de->vfs_created) return -EPERM;
+    /*  First ensure the directory is empty and will stay thay way  */
+    write_lock (&de->u.dir.lock);
+    de->u.dir.no_more_additions = TRUE;
+    if (de->u.dir.first) err = -ENOTEMPTY;
+    write_unlock (&de->u.dir.lock);
+    if (err) return err;
+    /*  Now unhook the directory from it's parent  */
+    write_lock (&de->parent->u.dir.lock);
+    if ( !_devfs_unhook (de) ) err = -ENOENT;
+    write_unlock (&de->parent->u.dir.lock);
+    if (err) return err;
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info, 0);
+    free_dentry (de);
+    devfs_put (de);
     return 0;
 }   /*  End Function devfs_rmdir  */
 
 static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
 			int rdev)
 {
-    int is_new;
-    struct fs_info *fs_info;
+    int err;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
 #ifdef CONFIG_DEVFS_DEBUG
-    char txt[STRING_LENGTH];
-
     if (devfs_debug & DEBUG_I_MKNOD)
-    {
-	memset (txt, 0, STRING_LENGTH);
-	memcpy (txt, dentry->d_name.name, dentry->d_name.len);
-	txt[STRING_LENGTH - 1] = '\0';
 	printk ("%s: mknod(%s): mode: 0%o  dev: %d\n",
-		DEVFS_NAME, txt, mode, rdev);
-    }
+		DEVFS_NAME, dentry->d_name.name, mode, rdev);
 #endif
-
-    fs_info = dir->i_sb->u.generic_sbp;
-    /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
-    /*  Try to reclaim an existing devfs entry, create if there isn't one  */
-    de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
-			   FALSE, TRUE, &is_new, FALSE);
-    if (de == NULL) return -ENOMEM;
-    if (de->registered)
-    {
-	printk ("%s: mknod(): existing entry\n", DEVFS_NAME);
-	return -EEXIST;
-    }
-    de->info = NULL;
-    de->mode = mode;
+    de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
+    if (!de) return -ENOMEM;
+    de->vfs_created = TRUE;
     if ( S_ISBLK (mode) || S_ISCHR (mode) )
     {
 	de->u.fcb.u.device.major = MAJOR (rdev);
 	de->u.fcb.u.device.minor = MINOR (rdev);
-	de->u.fcb.default_uid = current->euid;
-	de->u.fcb.default_gid = current->egid;
-	de->u.fcb.ops = NULL;
-	de->u.fcb.auto_owner = FALSE;
-	de->u.fcb.aopen_notify = FALSE;
-	de->u.fcb.open = FALSE;
     }
-    else if ( S_ISFIFO (mode) )
-    {
-	de->u.fifo.uid = current->euid;
-	de->u.fifo.gid = current->egid;
-    }
-    de->hide = FALSE;
-    de->inode.mode = mode;
+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
+	return err;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    de->registered = TRUE;
     if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
 #ifdef CONFIG_DEVFS_DEBUG
@@ -3011,8 +3086,9 @@
 		DEVFS_NAME, de->inode.ino, inode, dentry);
 #endif
     d_instantiate (dentry, inode);
-    devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info, 0);
     return 0;
 }   /*  End Function devfs_mknod  */
 
@@ -3021,12 +3097,9 @@
     int err;
     struct devfs_entry *de;
 
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
     if (!de) return -ENODEV;
-    down_read (&symlink_rwsem);
-    err = de->registered ? vfs_readlink (dentry, buffer, buflen,
-					 de->u.symlink.linkname) : -ENODEV;
-    up_read (&symlink_rwsem);
+    err = vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname);
     return err;
 }   /*  End Function devfs_readlink  */
 
@@ -3034,25 +3107,10 @@
 {
     int err;
     struct devfs_entry *de;
-    char *copy;
 
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
     if (!de) return -ENODEV;
-    down_read (&symlink_rwsem);
-    if (!de->registered)
-    {
-	up_read (&symlink_rwsem);
-	return -ENODEV;
-    }
-    copy = kmalloc (de->u.symlink.length + 1, GFP_KERNEL);
-    if (copy) memcpy (copy, de->u.symlink.linkname, de->u.symlink.length + 1);
-    up_read (&symlink_rwsem);
-    if (copy)
-    {
-	err = vfs_follow_link (nd, copy);
-	kfree (copy);
-    }
-    else err = -ENOMEM;
+    err = vfs_follow_link (nd, de->u.symlink.linkname);
     return err;
 }   /*  End Function devfs_follow_link  */
 
@@ -3084,7 +3142,7 @@
 {
     struct inode *root_inode = NULL;
 
-    if (get_root_entry () == NULL) goto out_no_root;
+    if (_devfs_get_root_entry () == NULL) goto out_no_root;
     atomic_set (&fs_info.devfsd_overrun_count, 0);
     init_waitqueue_head (&fs_info.devfsd_wait_queue);
     init_waitqueue_head (&fs_info.revalidate_wait_queue);
@@ -3099,7 +3157,7 @@
     sb->s_root = d_alloc_root (root_inode);
     if (!sb->s_root) goto out_no_root;
 #ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_DISABLED)
+    if (devfs_debug & DEBUG_S_READ)
 	printk ("%s: read super, made devfs ptr: %p\n",
 		DEVFS_NAME, sb->u.generic_sbp);
 #endif
@@ -3123,6 +3181,7 @@
     int done = FALSE;
     int ival;
     loff_t pos, devname_offset, tlen, rpos;
+    devfs_handle_t de;
     struct devfsd_buf_entry *entry;
     struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->u.generic_sbp;
     struct devfsd_notify_struct *info = fs_info->devfsd_info;
@@ -3149,40 +3208,28 @@
 	    current->state = TASK_RUNNING;
 	    return -EINTR;
 	}
-	set_current_state(TASK_INTERRUPTIBLE);
+	set_current_state (TASK_INTERRUPTIBLE);
     }
     remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
     current->state = TASK_RUNNING;
     /*  Now play with the data  */
     ival = atomic_read (&fs_info->devfsd_overrun_count);
-    if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
     info->overrun_count = ival;
-    entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer +
-	fs_info->devfsd_buf_out;
+    entry = fs_info->devfsd_first_event;
     info->type = entry->type;
     info->mode = entry->mode;
     info->uid = entry->uid;
     info->gid = entry->gid;
-    if (entry->type == DEVFSD_NOTIFY_LOOKUP)
+    de = entry->de;
+    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) )
     {
-	info->namelen = strlen (entry->data);
-	pos = 0;
-	memcpy (info->devname, entry->data, info->namelen + 1);
-    }
-    else
-    {
-	devfs_handle_t de = entry->data;
-
-	if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-	{
-	    info->major = de->u.fcb.u.device.major;
-	    info->minor = de->u.fcb.u.device.minor;
-	}
-	pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
-	if (pos < 0) return pos;
-	info->namelen = DEVFS_PATHLEN - pos - 1;
-	if (info->mode == 0) info->mode = de->mode;
+	info->major = de->u.fcb.u.device.major;
+	info->minor = de->u.fcb.u.device.minor;
     }
+    pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
+    if (pos < 0) return pos;
+    info->namelen = DEVFS_PATHLEN - pos - 1;
+    if (info->mode == 0) info->mode = de->mode;
     devname_offset = info->devname - (char *) info;
     rpos = *ppos;
     if (rpos < devname_offset)
@@ -3214,10 +3261,19 @@
     tlen = rpos - *ppos;
     if (done)
     {
-	unsigned int next_pos = fs_info->devfsd_buf_out + 1;
+	devfs_handle_t parent;
 
-	if (next_pos >= devfsd_buf_size) next_pos = 0;
-	fs_info->devfsd_buf_out = next_pos;
+	spin_lock (&fs_info->devfsd_buffer_lock);
+	fs_info->devfsd_first_event = entry->next;
+	if (entry->next == NULL) fs_info->devfsd_last_event = NULL;
+	spin_unlock (&fs_info->devfsd_buffer_lock);
+	for (; de != NULL; de = parent)
+	{
+	    parent = de->parent;
+	    devfs_put (de);
+	}
+	kmem_cache_free (devfsd_buf_cache, entry);
+	if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
 	*ppos = 0;
     }
     else *ppos = rpos;
@@ -3252,16 +3308,16 @@
 	    }
 	    fs_info->devfsd_task = current;
 	    spin_unlock (&lock);
+	    fs_info->devfsd_pgrp = (current->pgrp == current->pid) ?
+		current->pgrp : 0;
 	    fs_info->devfsd_file = file;
-	    fs_info->devfsd_buffer = (void *) __get_free_page (GFP_KERNEL);
 	    fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
 					    GFP_KERNEL);
-	    if (!fs_info->devfsd_buffer || !fs_info->devfsd_info)
+	    if (!fs_info->devfsd_info)
 	    {
 		devfsd_close (inode, file);
 		return -ENOMEM;
 	    }
-	    fs_info->devfsd_buf_out = fs_info->devfsd_buf_in;
 	}
 	else if (fs_info->devfsd_task != current) return -EBUSY;
 	fs_info->devfsd_event_mask = arg;  /*  Let the masses come forth  */
@@ -3284,29 +3340,52 @@
 
 static int devfsd_close (struct inode *inode, struct file *file)
 {
-    unsigned long flags;
+    struct devfsd_buf_entry *entry, *next;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
     if (fs_info->devfsd_file != file) return 0;
     fs_info->devfsd_event_mask = 0;
     fs_info->devfsd_file = NULL;
-    spin_lock_irqsave (&fs_info->devfsd_buffer_lock, flags);
-    if (fs_info->devfsd_buffer)
-    {
-	free_page ( (unsigned long) fs_info->devfsd_buffer );
-	fs_info->devfsd_buffer = NULL;
-    }
+    spin_lock (&fs_info->devfsd_buffer_lock);
+    entry = fs_info->devfsd_first_event;
+    fs_info->devfsd_first_event = NULL;
+    fs_info->devfsd_last_event = NULL;
     if (fs_info->devfsd_info)
     {
 	kfree (fs_info->devfsd_info);
 	fs_info->devfsd_info = NULL;
     }
-    spin_unlock_irqrestore (&fs_info->devfsd_buffer_lock, flags);
+    spin_unlock (&fs_info->devfsd_buffer_lock);
+    fs_info->devfsd_pgrp = 0;
     fs_info->devfsd_task = NULL;
     wake_up (&fs_info->revalidate_wait_queue);
+    for (; entry; entry = next)
+    {
+	next = entry->next;
+	kmem_cache_free (devfsd_buf_cache, entry);
+    }
     return 0;
 }   /*  End Function devfsd_close  */
 
+#ifdef CONFIG_DEVFS_DEBUG
+static ssize_t stat_read (struct file *file, char *buf, size_t len,
+			  loff_t *ppos)
+{
+    ssize_t num;
+    char txt[80];
+
+    num = sprintf (txt, "Number of entries: %u  number of bytes: %u\n",
+		   stat_num_entries, stat_num_bytes) + 1;
+    /*  Can't seek (pread) on this device  */
+    if (ppos != &file->f_pos) return -ESPIPE;
+    if (*ppos >= num) return 0;
+    if (*ppos + len > num) len = num - *ppos;
+    if ( copy_to_user (buf, txt + *ppos, len) ) return -EFAULT;
+    *ppos += len;
+    return len;
+}   /*  End Function stat_read  */
+#endif
+
 
 static int __init init_devfs_fs (void)
 {
@@ -3333,6 +3412,9 @@
 {
     int err;
 
+    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
+					  sizeof (struct devfsd_buf_entry),
+					  0, 0, NULL, NULL);
     if ( !(boot_options & OPTION_MOUNT) ) return;
     err = do_mount ("none", "/dev", "devfs", 0, "");
     if (err == 0) printk ("Mounted devfs on /dev\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/devpts/root.c linux/fs/devpts/root.c
--- linux-2.4.16/fs/devpts/root.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/devpts/root.c	Fri Dec  7 19:03:00 2001
@@ -101,7 +101,6 @@
 	int i;
 	const char *p;
 
-	dentry->d_inode = NULL;	/* Assume failure */
 	dentry->d_op    = &devpts_dentry_operations;
 
 	if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
@@ -127,11 +126,10 @@
 	if ( entry >= sbi->max_ptys )
 		return NULL;
 
-	dentry->d_inode = sbi->inodes[entry];
-	if ( dentry->d_inode )
-		atomic_inc(&dentry->d_inode->i_count);
+	if ( sbi->inodes[entry] )
+		atomic_inc(&sbi->inodes[entry]->i_count);
 	
-	d_add(dentry, dentry->d_inode);
+	d_add(dentry, sbi->inodes[entry]);
 
 	return NULL;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/exec.c linux/fs/exec.c
--- linux-2.4.16/fs/exec.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/exec.c	Thu Dec  6 19:57:21 2001
@@ -586,7 +586,7 @@
 flush_failed:
 	spin_lock_irq(&current->sigmask_lock);
 	if (current->sig != oldsig) {
-		kfree(current->sig);
+		kmem_cache_free(sigact_cachep, current->sig);
 		current->sig = oldsig;
 	}
 	spin_unlock_irq(&current->sigmask_lock);
@@ -973,9 +973,7 @@
 	if (do_truncate(file->f_dentry, 0) != 0)
 		goto close_fail;
 
-	down_read(&current->mm->mmap_sem);
 	retval = binfmt->core_dump(signr, regs, file);
-	up_read(&current->mm->mmap_sem);
 
 close_fail:
 	filp_close(file, NULL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ext2/super.c linux/fs/ext2/super.c
--- linux-2.4.16/fs/ext2/super.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/ext2/super.c	Tue Dec  4 19:25:31 2001
@@ -28,6 +28,8 @@
 #include <asm/uaccess.h>
 
 
+static void ext2_sync_super(struct super_block *sb,
+			    struct ext2_super_block *es);
 
 static char error_buf[1024];
 
@@ -35,13 +37,13 @@
 		 const char * fmt, ...)
 {
 	va_list args;
+	struct ext2_super_block *es = EXT2_SB(sb)->s_es;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
-		sb->u.ext2_sb.s_es->s_state =
-			cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
-		sb->s_dirt = 1;
+		es->s_state =
+			cpu_to_le16(le16_to_cpu(es->s_state) | EXT2_ERROR_FS);
+		ext2_sync_super(sb, es);
 	}
 	va_start (args, fmt);
 	vsprintf (error_buf, fmt, args);
@@ -124,8 +126,10 @@
 	int i;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
-		sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
+		struct ext2_super_block *es = EXT2_SB(sb)->s_es;
+
+		es->s_state = le16_to_cpu(EXT2_SB(sb)->s_mount_state);
+		ext2_sync_super(sb, es);
 	}
 	db_count = EXT2_SB(sb)->s_gdb_count;
 	for (i = 0; i < db_count; i++)
@@ -305,13 +309,10 @@
 		(le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
 		printk ("EXT2-fs warning: checktime reached, "
 			"running e2fsck is recommended\n");
-	es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
 	if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
 		es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
 	es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
-	es->s_mtime = cpu_to_le32(CURRENT_TIME);
-	mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
-	sb->s_dirt = 1;
+	ext2_write_super(sb);
 	if (test_opt (sb, DEBUG))
 		printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
 			"bpg=%lu, ipg=%lu, mo=%04lx]\n",
@@ -664,6 +665,15 @@
 	sb->s_dirt = 0;
 }
 
+static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es)
+{
+	es->s_wtime = cpu_to_le32(CURRENT_TIME);
+	mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
+	ll_rw_block(WRITE, 1, &EXT2_SB(sb)->s_sbh);
+	wait_on_buffer(EXT2_SB(sb)->s_sbh);
+	sb->s_dirt = 0;
+}
+
 /*
  * In the second extended file system, it is not necessary to
  * write the super block since we use a mapping of the
@@ -682,13 +692,14 @@
 	if (!(sb->s_flags & MS_RDONLY)) {
 		es = sb->u.ext2_sb.s_es;
 
-		ext2_debug ("setting valid to 0\n");
-
 		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) {
-			es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+			ext2_debug ("setting valid to 0\n");
+			es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) &
+						  ~EXT2_VALID_FS);
 			es->s_mtime = cpu_to_le32(CURRENT_TIME);
-		}
-		ext2_commit_super (sb, es);
+			ext2_sync_super(sb, es);
+		} else
+			ext2_commit_super (sb, es);
 	}
 	sb->s_dirt = 0;
 }
@@ -725,11 +736,7 @@
 		 */
 		es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state);
 		es->s_mtime = cpu_to_le32(CURRENT_TIME);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
-		sb->s_dirt = 1;
-		ext2_commit_super (sb, es);
-	}
-	else {
+	} else {
 		int ret;
 		if ((ret = EXT2_HAS_RO_COMPAT_FEATURE(sb,
 					       ~EXT2_FEATURE_RO_COMPAT_SUPP))) {
@@ -747,6 +754,7 @@
 		if (!ext2_setup_super (sb, es, 0))
 			sb->s_flags &= ~MS_RDONLY;
 	}
+	ext2_sync_super(sb, es);
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ext3/Makefile linux/fs/ext3/Makefile
--- linux-2.4.16/fs/ext3/Makefile	Mon Nov 26 10:35:00 2001
+++ linux/fs/ext3/Makefile	Thu Dec  6 20:42:51 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := ext3.o
 
-obj-y    := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 		ioctl.o namei.o super.o symlink.o
 obj-m    := $(O_TARGET)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ext3/acl.c linux/fs/ext3/acl.c
--- linux-2.4.16/fs/ext3/acl.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/ext3/acl.c	Thu Jan  1 00:00:00 1970
@@ -1,17 +0,0 @@
-/*
- * linux/fs/ext3/acl.c
- *
- * Copyright (C) 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-
-
-/*
- * This file will contain the Access Control Lists management for the
- * second extended file system.
- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ext3/inode.c linux/fs/ext3/inode.c
--- linux-2.4.16/fs/ext3/inode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/ext3/inode.c	Sun Dec  9 22:02:44 2001
@@ -32,7 +32,6 @@
 #include <linux/quotaops.h>
 #include <linux/module.h>
 
-
 /*
  * SEARCH_FROM_ZERO forces each block allocation to search from the start
  * of the filesystem.  This is to force rapid reallocation of recently-freed
@@ -716,6 +715,8 @@
  * reachable from inode.
  *
  * akpm: `handle' can be NULL if create == 0.
+ *
+ * The BKL may not be held on entry here.  Be sure to take it early.
  */
 
 static int ext3_get_block_handle(handle_t *handle, struct inode *inode, 
@@ -823,6 +824,9 @@
 	goto reread;
 }
 
+/*
+ * The BKL is not held on entry here.
+ */
 static int ext3_get_block(struct inode *inode, long iblock,
 			struct buffer_head *bh_result, int create)
 {
@@ -1022,13 +1026,26 @@
 		ret = PTR_ERR(handle);
 		goto out;
 	}
+	unlock_kernel();
 	ret = block_prepare_write(page, from, to, ext3_get_block);
+	lock_kernel();
 	if (ret != 0)
 		goto prepare_write_failed;
 
-	if (ext3_should_journal_data(inode))
+	if (ext3_should_journal_data(inode)) {
 		ret = walk_page_buffers(handle, page->buffers,
 				from, to, NULL, do_journal_get_write_access);
+		if (ret) {
+			/*
+			 * We're going to fail this prepare_write(),
+			 * so commit_write() will not be called.
+			 * We need to undo block_prepare_write()'s kmap().
+			 * AKPM: Do we need to clear PageUptodate?  I don't
+			 * think so.
+			 */
+			kunmap(page);
+		}
+	}
 prepare_write_failed:
 	if (ret)
 		ext3_journal_stop(handle, inode);
@@ -1096,7 +1113,7 @@
 		kunmap(page);
 		if (pos > inode->i_size)
 			inode->i_size = pos;
-		set_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state);
+		EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
 	} else {
 		if (ext3_should_order_data(inode)) {
 			ret = walk_page_buffers(handle, page->buffers,
@@ -1104,8 +1121,17 @@
 		}
 		/* Be careful here if generic_commit_write becomes a
 		 * required invocation after block_prepare_write. */
-		if (ret == 0)
+		if (ret == 0) {
 			ret = generic_commit_write(file, page, from, to);
+		} else {
+			/*
+			 * block_prepare_write() was called, but we're not
+			 * going to call generic_commit_write().  So we
+			 * need to perform generic_commit_write()'s kunmap
+			 * by hand.
+			 */
+			kunmap(page);
+		}
 	}
 	if (inode->i_size > inode->u.ext3_i.i_disksize) {
 		inode->u.ext3_i.i_disksize = inode->i_size;
@@ -1140,7 +1166,7 @@
 	journal_t *journal;
 	int err;
 	
-	if (test_and_clear_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state)) {
+	if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) {
 		/* 
 		 * This is a REALLY heavyweight approach, but the use of
 		 * bmap on dirty files is expected to be extremely rare:
@@ -1159,6 +1185,7 @@
 		 * everything they get.
 		 */
 		
+		EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA;
 		journal = EXT3_JOURNAL(inode);
 		journal_lock_updates(journal);
 		err = journal_flush(journal);
@@ -2203,7 +2230,7 @@
 	/* If we are not tracking these fields in the in-memory inode,
 	 * then preserve them on disk, but still initialise them to zero
 	 * for new inodes. */
-	if (inode->u.ext3_i.i_state & EXT3_STATE_NEW) {
+	if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {
 		raw_inode->i_faddr = 0;
 		raw_inode->i_frag = 0;
 		raw_inode->i_fsize = 0;
@@ -2249,7 +2276,7 @@
 	rc = ext3_journal_dirty_metadata(handle, bh);
 	if (!err)
 		err = rc;
-	inode->u.ext3_i.i_state &= ~EXT3_STATE_NEW;
+	EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW;
 
 out_brelse:
 	brelse (bh);
@@ -2333,12 +2360,20 @@
 int ext3_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
-	int error, rc;
+	int error, rc = 0;
+	const unsigned int ia_valid = attr->ia_valid;
 
 	error = inode_change_ok(inode, attr);
 	if (error)
 		return error;
-	
+
+	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+		error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+		if (error)
+			return error;
+	}
+
 	if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
 		handle_t *handle;
 
@@ -2356,7 +2391,7 @@
 		ext3_journal_stop(handle, inode);
 	}
 	
-	inode_setattr(inode, attr);
+	rc = inode_setattr(inode, attr);
 
 	/* If inode_setattr's call to ext3_truncate failed to get a
 	 * transaction handle at all, we need to clean up the in-core
@@ -2366,7 +2401,9 @@
 
 err_out:
 	ext3_std_error(inode->i_sb, error);
-	return 0;
+	if (!error)
+		error = rc;
+	return error;
 }
 
 
@@ -2667,6 +2704,3 @@
  * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we
  * need to extend" test in ext3_prepare_write() succeeds.  
  */
-
-
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ext3/super.c linux/fs/ext3/super.c
--- linux-2.4.16/fs/ext3/super.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/ext3/super.c	Thu Dec  6 20:42:51 2001
@@ -1257,8 +1257,11 @@
 	}
 
 	journal = journal_init_inode(journal_inode);
-	if (!journal)
+	if (!journal) {
+		printk(KERN_ERR "EXT3-fs: Could not load journal inode\n");
 		iput(journal_inode);
+	}
+	
 	return journal;
 }
 
@@ -1350,7 +1353,7 @@
 	journal_t *journal;
 	int journal_inum = le32_to_cpu(es->s_journal_inum);
 	int journal_dev = le32_to_cpu(es->s_journal_dev);
-	int err;
+	int err = 0;
 	int really_read_only;
 
 	really_read_only = is_read_only(sb->s_dev);
@@ -1400,9 +1403,10 @@
 	}
 
 	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER))
-		journal_wipe(journal, !really_read_only);
+		err = journal_wipe(journal, !really_read_only);
+	if (!err)
+		err = journal_load(journal);
 
-	err = journal_load(journal);
 	if (err) {
 		printk(KERN_ERR "EXT3-fs: error loading journal.\n");
 		journal_destroy(journal);
@@ -1740,6 +1744,8 @@
 
 EXPORT_NO_SYMBOLS;
 
+MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
+MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions");
 MODULE_LICENSE("GPL");
 module_init(init_ext3_fs)
 module_exit(exit_ext3_fs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/inflate_fs/inflate_syms.c linux/fs/inflate_fs/inflate_syms.c
--- linux-2.4.16/fs/inflate_fs/inflate_syms.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/inflate_fs/inflate_syms.c	Tue Dec  4 19:25:31 2001
@@ -19,3 +19,4 @@
 EXPORT_SYMBOL(zlib_fs_inflateReset);
 EXPORT_SYMBOL(zlib_fs_adler32);
 EXPORT_SYMBOL(zlib_fs_inflateSyncPoint);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/inode.c linux/fs/inode.c
--- linux-2.4.16/fs/inode.c	Mon Nov 26 10:35:11 2001
+++ linux/fs/inode.c	Tue Dec  4 19:25:31 2001
@@ -1072,7 +1072,7 @@
 				}
 				inodes_stat.nr_unused++;
 				spin_unlock(&inode_lock);
-				if (!sb || sb->s_flags & MS_ACTIVE)
+				if (!sb || (sb->s_flags & MS_ACTIVE))
 					return;
 				write_inode_now(inode, 1);
 				spin_lock(&inode_lock);
@@ -1187,6 +1187,8 @@
  
 void update_atime (struct inode *inode)
 {
+	if (inode->i_atime == CURRENT_TIME)
+		return;
 	if ( IS_NOATIME (inode) ) return;
 	if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
 	if ( IS_RDONLY (inode) ) return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/intermezzo/file.c linux/fs/intermezzo/file.c
--- linux-2.4.16/fs/intermezzo/file.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/intermezzo/file.c	Tue Dec  4 19:25:31 2001
@@ -344,7 +344,7 @@
                 << file->f_dentry->d_inode->i_sb->s_blocksize_bits);
 
         error = presto_reserve_space(fset->fset_cache, res_size); 
-        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
+        CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); 
         if ( error ) { 
                 EXIT;
                 return -ENOSPC;
@@ -397,7 +397,7 @@
         fops = filter_c2cffops(cache->cache_filter);
         res = fops->write(file, buf, size, off);
         if ( res != size ) {
-                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
+                CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); 
         }
 
         if ( (res > 0) && fdata ) 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/intermezzo/journal.c linux/fs/intermezzo/journal.c
--- linux-2.4.16/fs/intermezzo/journal.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/intermezzo/journal.c	Tue Dec  4 19:25:31 2001
@@ -1077,7 +1077,7 @@
                 return 0;
         }
 
-        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", 
+        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", 
                (long)lml_offset, sizeof(record));
         rc = presto_fread(fset->fset_lml.fd_file, (char *)&record,
                           sizeof(record), &offset);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/intermezzo/psdev.c linux/fs/intermezzo/psdev.c
--- linux-2.4.16/fs/intermezzo/psdev.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/intermezzo/psdev.c	Tue Dec  4 19:25:31 2001
@@ -176,7 +176,7 @@
 
         /* move data into response buffer. */
         if (req->rq_bufsize < count) {
-                printk("psdev_write: too much cnt: %d, cnt: %d, "
+                printk("psdev_write: too much cnt: %d, cnt: %Zd, "
                        "opc: %d, uniq: %d.\n",
                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
                 count = req->rq_bufsize; /* don't have more space! */
@@ -209,7 +209,7 @@
                        __FUNCTION__, kdevname(dev));
         }
 
-        CDEBUG(D_PSDEV, "count %d\n", count);
+        CDEBUG(D_PSDEV, "count %Zd\n", count);
         if (list_empty(&(upccom->uc_pending))) {
                 CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");
                 return -EINVAL;
@@ -228,7 +228,7 @@
         }
 
         if (count < req->rq_bufsize) {
-                printk ("psdev_read: buffer too small, read %d of %d bytes\n",
+                printk ("psdev_read: buffer too small, read %Zd of %d bytes\n",
                         count, req->rq_bufsize);
         }
 
@@ -281,7 +281,7 @@
                 error = copy_from_user(&readmount, (void *)arg,
                                        sizeof(readmount));
                 if ( error )  {
-                        printk("psdev: can't copy %d bytes from %p to %p\n",
+                        printk("psdev: can't copy %Zd bytes from %p to %p\n",
                                 sizeof(readmount), (struct readmount *) arg,
                                 &readmount);
                         EXIT;
@@ -469,7 +469,7 @@
                 input.size = size;
                 upccom->uc_pid = saved_pid;
 
-                CDEBUG(D_PSDEV, "get_kmlsize: size = %d\n", size);
+                CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size);
 
                 EXIT;
                 return copy_to_user((char *)arg, &input, sizeof(input));
@@ -621,7 +621,7 @@
 
                 error = copy_from_user(&kopt, (void *)arg, sizeof(kopt));
                 if ( error )  {
-                        printk("psdev: can't copyin %d bytes from %p to %p\n",
+                        printk("psdev: can't copyin %Zd bytes from %p to %p\n",
                                sizeof(kopt), (struct kopt *) arg, &kopt);
                         EXIT;
                         return error;
@@ -1244,7 +1244,7 @@
         
         default:
                 CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd);
-                CDEBUG(D_PSDEV, "valid are 0x%x - 0x%x, 0x%x - 0x%x \n",
+                CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n",
                         PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
                         PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
                 EXIT;
@@ -1571,8 +1571,8 @@
                req->rq_opcode, jiffies - req->rq_posttime,
                req->rq_unique, req->rq_rep_size);
         CDEBUG(D_UPCALL,
-               "..process %d woken up by Lento for req at 0x%x, data at %x\n",
-               current->pid, (int)req, (int)req->rq_data);
+               "..process %d woken up by Lento for req at 0x%p, data at %p\n",
+               current->pid, req, req->rq_data);
 
         if (upc_commp->uc_pid) {      /* i.e. Lento is still alive */
           /* Op went through, interrupt or not we go on */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/jbd/commit.c linux/fs/jbd/commit.c
--- linux-2.4.16/fs/jbd/commit.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/jbd/commit.c	Thu Dec  6 20:42:51 2001
@@ -47,7 +47,8 @@
 	struct buffer_head *wbuf[64];
 	int bufs;
 	int flags;
-	int blocknr;
+	int err;
+	unsigned long blocknr;
 	char *tagp = NULL;
 	journal_header_t *header;
 	journal_block_tag_t *tag = NULL;
@@ -352,6 +353,11 @@
 			jbd_debug(4, "JBD: get descriptor\n");
 
 			descriptor = journal_get_descriptor_buffer(journal);
+			if (!descriptor) {
+				__journal_abort_hard(journal);
+				continue;
+			}
+			
 			bh = jh2bh(descriptor);
 			jbd_debug(4, "JBD: got buffer %ld (%p)\n",
 				bh->b_blocknr, bh->b_data);
@@ -375,7 +381,14 @@
 
 		/* Where is the buffer to be written? */
 
-		blocknr = journal_next_log_block(journal);
+		err = journal_next_log_block(journal, &blocknr);
+		/* If the block mapping failed, just abandon the buffer
+		   and repeat this loop: we'll fall into the
+		   refile-on-abort condition above. */
+		if (err) {
+			__journal_abort_hard(journal);
+			continue;
+		}
 
 		/* Bump b_count to prevent truncate from stumbling over
                    the shadowed buffer!  @@@ This can go if we ever get
@@ -554,16 +567,20 @@
 
 	jbd_debug(3, "JBD: commit phase 6\n");
 
+	if (is_journal_aborted(journal))
+		goto skip_commit;
+
 	/* Done it all: now write the commit record.  We should have
 	 * cleaned up our previous buffers by now, so if we are in abort
 	 * mode we can now just skip the rest of the journal write
 	 * entirely. */
 
-	if (is_journal_aborted(journal))
-		goto skip_commit;
-
 	descriptor = journal_get_descriptor_buffer(journal);
-
+	if (!descriptor) {
+		__journal_abort_hard(journal);
+		goto skip_commit;
+	}
+	
 	/* AKPM: buglet - add `i' to tmp! */
 	for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) {
 		journal_header_t *tmp =
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/jbd/journal.c linux/fs/jbd/journal.c
--- linux-2.4.16/fs/jbd/journal.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/jbd/journal.c	Thu Dec  6 20:42:51 2001
@@ -70,7 +70,6 @@
 EXPORT_SYMBOL(journal_destroy);
 EXPORT_SYMBOL(journal_recover);
 EXPORT_SYMBOL(journal_update_superblock);
-EXPORT_SYMBOL(__journal_abort);
 EXPORT_SYMBOL(journal_abort);
 EXPORT_SYMBOL(journal_errno);
 EXPORT_SYMBOL(journal_ack_err);
@@ -606,7 +605,7 @@
  * Log buffer allocation routines:
  */
 
-unsigned long journal_next_log_block(journal_t *journal)
+int journal_next_log_block(journal_t *journal, unsigned long *retp)
 {
 	unsigned long blocknr;
 
@@ -617,7 +616,7 @@
 	journal->j_free--;
 	if (journal->j_head == journal->j_last)
 		journal->j_head = journal->j_first;
-	return journal_bmap(journal, blocknr);
+	return journal_bmap(journal, blocknr, retp);
 }
 
 /*
@@ -627,17 +626,28 @@
  * this is a no-op.  If needed, we can use j_blk_offset - everything is
  * ready.
  */
-unsigned long journal_bmap(journal_t *journal, unsigned long blocknr)
+int journal_bmap(journal_t *journal, unsigned long blocknr, 
+		 unsigned long *retp)
 {
+	int err = 0;
 	unsigned long ret;
 
 	if (journal->j_inode) {
 		ret = bmap(journal->j_inode, blocknr);
-		J_ASSERT(ret != 0);
+		if (ret)
+			*retp = ret;
+		else {
+			printk (KERN_ALERT __FUNCTION__ 
+				": journal block not found "
+				"at offset %lu on %s\n",
+				blocknr, bdevname(journal->j_dev));
+			err = -EIO;
+			__journal_abort_soft(journal, err);
+		}
 	} else {
-		ret = blocknr;	 /* +journal->j_blk_offset */
+		*retp = blocknr; /* +journal->j_blk_offset */
 	}
-	return ret;
+	return err;
 }
 
 /*
@@ -649,7 +659,13 @@
 struct journal_head * journal_get_descriptor_buffer(journal_t *journal)
 {
 	struct buffer_head *bh;
-	unsigned long blocknr = journal_next_log_block(journal);
+	unsigned long blocknr;
+	int err;
+
+	err = journal_next_log_block(journal, &blocknr);
+
+	if (err)
+		return NULL;
 
 	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
 	bh->b_state |= (1 << BH_Dirty);
@@ -747,7 +763,8 @@
 {
 	struct buffer_head *bh;
 	journal_t *journal = journal_init_common();
-	int blocknr;
+	int err;
+	unsigned long blocknr;
 
 	if (!journal)
 		return NULL;
@@ -757,13 +774,22 @@
 	journal->j_inode = inode;
 	jbd_debug(1,
 		  "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
-		  journal, bdevname(inode->i_dev), inode->i_ino, inode->i_size,
+		  journal, bdevname(inode->i_dev), inode->i_ino, 
+		  (long long) inode->i_size,
 		  inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
 
 	journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
 	journal->j_blocksize = inode->i_sb->s_blocksize;
 
-	blocknr = journal_bmap(journal, 0);
+	err = journal_bmap(journal, 0, &blocknr);
+	/* If that failed, give up */
+	if (err) {
+		printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal "
+		       "superblock\n");
+		kfree(journal);
+		return NULL;
+	}
+	
 	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
 	J_ASSERT(bh != NULL);
 	journal->j_sb_buffer = bh;
@@ -772,6 +798,18 @@
 	return journal;
 }
 
+/* 
+ * If the journal init or create aborts, we need to mark the journal
+ * superblock as being NULL to prevent the journal destroy from writing
+ * back a bogus superblock. 
+ */
+static void journal_fail_superblock (journal_t *journal)
+{
+	struct buffer_head *bh = journal->j_sb_buffer;
+	brelse(bh);
+	journal->j_sb_buffer = NULL;
+}
+
 /*
  * Given a journal_t structure, initialise the various fields for
  * startup of a new journaling session.  We use this both when creating
@@ -817,14 +855,15 @@
 
 int journal_create (journal_t *journal)
 {
-	int blocknr;
+	unsigned long blocknr;
 	struct buffer_head *bh;
 	journal_superblock_t *sb;
-	int i;
+	int i, err;
 
 	if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) {
 		printk (KERN_ERR "Journal length (%d blocks) too short.\n",
 			journal->j_maxlen);
+		journal_fail_superblock(journal);
 		return -EINVAL;
 	}
 
@@ -841,7 +880,9 @@
 	   have any blocks on disk beginning with JFS_MAGIC_NUMBER. */
 	jbd_debug(1, "JBD: Zeroing out journal blocks...\n");
 	for (i = 0; i < journal->j_maxlen; i++) {
-		blocknr = journal_bmap(journal, i);
+		err = journal_bmap(journal, i, &blocknr);
+		if (err)
+			return err;
 		bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
 		wait_on_buffer(bh);
 		memset (bh->b_data, 0, journal->j_blocksize);
@@ -851,6 +892,7 @@
 		mark_buffer_uptodate(bh, 1);
 		__brelse(bh);
 	}
+
 	sync_dev(journal->j_dev);
 	jbd_debug(1, "JBD: journal cleared.\n");
 
@@ -915,7 +957,8 @@
 {
 	struct buffer_head *bh;
 	journal_superblock_t *sb;
-
+	int err = -EIO;
+	
 	bh = journal->j_sb_buffer;
 
 	J_ASSERT(bh != NULL);
@@ -925,16 +968,18 @@
 		if (!buffer_uptodate(bh)) {
 			printk (KERN_ERR
 				"JBD: IO error reading journal superblock\n");
-			return -EIO;
+			goto out;
 		}
 	}
 
 	sb = journal->j_superblock;
 
+	err = -EINVAL;
+	
 	if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
 	    sb->s_blocksize != htonl(journal->j_blocksize)) {
 		printk(KERN_WARNING "JBD: no valid journal superblock found\n");
-		return -EINVAL;
+		goto out;
 	}
 
 	switch(ntohl(sb->s_header.h_blocktype)) {
@@ -946,17 +991,21 @@
 		break;
 	default:
 		printk(KERN_WARNING "JBD: unrecognised superblock format ID\n");
-		return -EINVAL;
+		goto out;
 	}
 
 	if (ntohl(sb->s_maxlen) < journal->j_maxlen)
 		journal->j_maxlen = ntohl(sb->s_maxlen);
 	else if (ntohl(sb->s_maxlen) > journal->j_maxlen) {
 		printk (KERN_WARNING "JBD: journal file too short\n");
-		return -EINVAL;
+		goto out;
 	}
 
 	return 0;
+
+out:
+	journal_fail_superblock(journal);
+	return err;
 }
 
 /*
@@ -1061,7 +1110,10 @@
 	/* We can now mark the journal as empty. */
 	journal->j_tail = 0;
 	journal->j_tail_sequence = ++journal->j_transaction_sequence;
-	journal_update_superblock(journal, 1);
+	if (journal->j_sb_buffer) {
+		journal_update_superblock(journal, 1);
+		brelse(journal->j_sb_buffer);
+	}
 
 	if (journal->j_inode)
 		iput(journal->j_inode);
@@ -1069,7 +1121,6 @@
 		journal_destroy_revoke(journal);
 
 	unlock_journal(journal);
-	brelse(journal->j_sb_buffer);
 	kfree(journal);
 	MOD_DEC_USE_COUNT;
 }
@@ -1356,11 +1407,16 @@
  * progress).
  */
 
-/* Quick version for internal journal use (doesn't lock the journal) */
-void __journal_abort (journal_t *journal)
+/* Quick version for internal journal use (doesn't lock the journal).
+ * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
+ * and don't attempt to make any other journal updates. */
+void __journal_abort_hard (journal_t *journal)
 {
 	transaction_t *transaction;
 
+	if (journal->j_flags & JFS_ABORT)
+		return;
+
 	printk (KERN_ERR "Aborting journal on device %s.\n",
 		journal_dev_name(journal));
 
@@ -1370,23 +1426,27 @@
 		log_start_commit(journal, transaction);
 }
 
-/* Full version for external use */
-void journal_abort (journal_t *journal, int errno)
+/* Soft abort: record the abort error status in the journal superblock,
+ * but don't do any other IO. */
+void __journal_abort_soft (journal_t *journal, int errno)
 {
-	lock_journal(journal);
-
 	if (journal->j_flags & JFS_ABORT)
-		goto out;
+		return;
 
 	if (!journal->j_errno)
 		journal->j_errno = errno;
 
-	__journal_abort(journal);
+	__journal_abort_hard(journal);
 
 	if (errno)
 		journal_update_superblock(journal, 1);
+}
 
- out:
+/* Full version for external use */
+void journal_abort (journal_t *journal, int errno)
+{
+	lock_journal(journal);
+	__journal_abort_soft(journal, errno);
 	unlock_journal(journal);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/jbd/recovery.c linux/fs/jbd/recovery.c
--- linux-2.4.16/fs/jbd/recovery.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/jbd/recovery.c	Thu Dec  6 20:42:51 2001
@@ -70,7 +70,8 @@
 static int do_readahead(journal_t *journal, unsigned int start)
 {
 	int err;
-	unsigned int max, nbufs, next, blocknr;
+	unsigned int max, nbufs, next;
+	unsigned long blocknr;
 	struct buffer_head *bh;
 	
 	struct buffer_head * bufs[MAXBUF];
@@ -86,12 +87,11 @@
 	nbufs = 0;
 	
 	for (next = start; next < max; next++) {
-		blocknr = journal_bmap(journal, next);
+		err = journal_bmap(journal, next, &blocknr);
 
-		if (!blocknr) {
+		if (err) {
 			printk (KERN_ERR "JBD: bad block at offset %u\n",
 				next);
-			err = -EIO;
 			goto failed;
 		}
 
@@ -132,19 +132,20 @@
 static int jread(struct buffer_head **bhp, journal_t *journal, 
 		 unsigned int offset)
 {
-	unsigned int blocknr;
+	int err;
+	unsigned long blocknr;
 	struct buffer_head *bh;
 
 	*bhp = NULL;
 
 	J_ASSERT (offset < journal->j_maxlen);
 	
-	blocknr = journal_bmap(journal, offset);
+	err = journal_bmap(journal, offset, &blocknr);
 
-	if (!blocknr) {
+	if (err) {
 		printk (KERN_ERR "JBD: bad block at offset %u\n",
 			offset);
-		return -EIO;
+		return err;
 	}
 
 	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/jbd/revoke.c linux/fs/jbd/revoke.c
--- linux-2.4.16/fs/jbd/revoke.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/jbd/revoke.c	Thu Dec  6 20:42:51 2001
@@ -495,6 +495,8 @@
 	
 	if (!descriptor) {
 		descriptor = journal_get_descriptor_buffer(journal);
+		if (!descriptor)
+			return;
 		header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
 		header->h_magic     = htonl(JFS_MAGIC_NUMBER);
 		header->h_blocktype = htonl(JFS_REVOKE_BLOCK);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/jbd/transaction.c linux/fs/jbd/transaction.c
--- linux-2.4.16/fs/jbd/transaction.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/jbd/transaction.c	Thu Dec  6 20:42:51 2001
@@ -1058,21 +1058,6 @@
 		JBUFFER_TRACE(jh, "not on a transaction");
 		__journal_file_buffer(jh, handle->h_transaction, wanted_jlist);
 	}
-	/*
-	 * We need to mark the buffer dirty and refile it inside the lock to
-	 * protect it from release by journal_try_to_free_buffer()
-	 *
-	 * We set ->b_flushtime to something small enough to typically keep
-	 * kupdate away from the buffer.
-	 *
-	 * We don't need to do a balance_dirty() - __block_commit_write()
-	 * does that.
-	 */
-	if (!async && !atomic_set_buffer_dirty(jh2bh(jh))) {
-		jh2bh(jh)->b_flushtime =
-			jiffies + journal->j_commit_interval + 1 * HZ;
-		refile_buffer(jh2bh(jh));
-	}
 no_journal:
 	spin_unlock(&journal_datalist_lock);
 	if (need_brelse) {
@@ -1604,8 +1589,6 @@
 
 	assert_spin_locked(&journal_datalist_lock);
 
-	if (!buffer_jbd(bh))
-		return 1;
 	jh = bh2jh(bh);
 
 	if (buffer_locked(bh) || buffer_dirty(bh)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- linux-2.4.16/fs/msdos/msdosfs_syms.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/msdos/msdosfs_syms.c	Tue Dec  4 19:25:31 2001
@@ -40,3 +40,4 @@
 
 module_init(init_msdos_fs)
 module_exit(exit_msdos_fs)
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/namespace.c linux/fs/namespace.c
--- linux-2.4.16/fs/namespace.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/namespace.c	Tue Dec  4 19:25:31 2001
@@ -19,9 +19,6 @@
 
 #include <asm/uaccess.h>
 
-#include <linux/nfs_fs.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/nfs_mount.h>
 #include <linux/seq_file.h>
 
 struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data);
@@ -198,50 +195,10 @@
 	seq_escape(m, s, " \t\n\\");
 }
 
-static void show_nfs_mount(struct seq_file *m, struct vfsmount *mnt)
-{
-	static struct proc_nfs_info {
-		int flag;
-		char *str;
-		char *nostr;
-	} nfs_info[] = {
-		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
-		{ NFS_MOUNT_INTR, ",intr", "" },
-		{ NFS_MOUNT_POSIX, ",posix", "" },
-		{ NFS_MOUNT_TCP, ",tcp", ",udp" },
-		{ NFS_MOUNT_NOCTO, ",nocto", "" },
-		{ NFS_MOUNT_NOAC, ",noac", "" },
-		{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
-		{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
-		{ 0, NULL, NULL }
-	};
-	struct proc_nfs_info *nfs_infop;
-	struct nfs_server *nfss = &mnt->mnt_sb->u.nfs_sb.s_server;
-
-	seq_printf(m, ",v%d", nfss->rpc_ops->version);
-	seq_printf(m, ",rsize=%d", nfss->rsize);
-	seq_printf(m, ",wsize=%d", nfss->wsize);
-	if (nfss->acregmin != 3*HZ)
-		seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
-	if (nfss->acregmax != 60*HZ)
-		seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
-	if (nfss->acdirmin != 30*HZ)
-		seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
-	if (nfss->acdirmax != 60*HZ)
-		seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
-	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
-		if (nfss->flags & nfs_infop->flag)
-			seq_puts(m, nfs_infop->str);
-		else
-			seq_puts(m, nfs_infop->nostr);
-	}
-	seq_puts(m, ",addr=");
-	mangle(m, nfss->hostname);
-}
-
 static int show_vfsmnt(struct seq_file *m, void *v)
 {
 	struct vfsmount *mnt = v;
+	int err = 0;
 	static struct proc_fs_info {
 		int flag;
 		char *str;
@@ -281,10 +238,10 @@
 		if (mnt->mnt_flags & fs_infop->flag)
 			seq_puts(m, fs_infop->str);
 	}
-	if (strcmp("nfs", mnt->mnt_sb->s_type->name) == 0)
-		show_nfs_mount(m, mnt);
+	if (mnt->mnt_sb->s_op->show_options)
+		err = mnt->mnt_sb->s_op->show_options(m, mnt);
 	seq_puts(m, " 0 0\n");
-	return 0;
+	return err;
 }
 
 struct seq_operations mounts_op = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- linux-2.4.16/fs/ncpfs/ncplib_kernel.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/ncpfs/ncplib_kernel.c	Tue Dec  4 19:25:31 2001
@@ -52,14 +52,6 @@
 	return;
 }
 
-static void ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size)
-{
-	assert_server_locked(server);
-	copy_from_user(&(server->packet[server->current_size]), source, size);
-	server->current_size += size;
-	return;
-}
-
 static void ncp_add_pstring(struct ncp_server *server, const char *s)
 {
 	int len = strlen(s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfs/inode.c linux/fs/nfs/inode.c
--- linux-2.4.16/fs/nfs/inode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfs/inode.c	Tue Dec  4 19:25:31 2001
@@ -32,6 +32,7 @@
 #include <linux/nfs_flushd.h>
 #include <linux/lockd/bind.h>
 #include <linux/smp_lock.h>
+#include <linux/seq_file.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -51,6 +52,7 @@
 static void nfs_clear_inode(struct inode *);
 static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct super_block *, struct statfs *);
+static int  nfs_show_options(struct seq_file *, struct vfsmount *);
 
 static struct super_operations nfs_sops = { 
 	read_inode:	nfs_read_inode,
@@ -60,6 +62,7 @@
 	statfs:		nfs_statfs,
 	clear_inode:	nfs_clear_inode,
 	umount_begin:	nfs_umount_begin,
+	show_options:	nfs_show_options,
 };
 
 /*
@@ -551,6 +554,48 @@
  out_err:
 	printk("nfs_statfs: statfs error = %d\n", -error);
 	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
+	return 0;
+}
+
+static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	static struct proc_nfs_info {
+		int flag;
+		char *str;
+		char *nostr;
+	} nfs_info[] = {
+		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
+		{ NFS_MOUNT_INTR, ",intr", "" },
+		{ NFS_MOUNT_POSIX, ",posix", "" },
+		{ NFS_MOUNT_TCP, ",tcp", ",udp" },
+		{ NFS_MOUNT_NOCTO, ",nocto", "" },
+		{ NFS_MOUNT_NOAC, ",noac", "" },
+		{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
+		{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+		{ 0, NULL, NULL }
+	};
+	struct proc_nfs_info *nfs_infop;
+	struct nfs_server *nfss = &mnt->mnt_sb->u.nfs_sb.s_server;
+
+	seq_printf(m, ",v%d", nfss->rpc_ops->version);
+	seq_printf(m, ",rsize=%d", nfss->rsize);
+	seq_printf(m, ",wsize=%d", nfss->wsize);
+	if (nfss->acregmin != 3*HZ)
+		seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+	if (nfss->acregmax != 60*HZ)
+		seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+	if (nfss->acdirmin != 30*HZ)
+		seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+	if (nfss->acdirmax != 60*HZ)
+		seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
+		if (nfss->flags & nfs_infop->flag)
+			seq_puts(m, nfs_infop->str);
+		else
+			seq_puts(m, nfs_infop->nostr);
+	}
+	seq_puts(m, ",addr=");
+	seq_escape(m, nfss->hostname, " \t\n\\");
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfs/nfs3proc.c linux/fs/nfs/nfs3proc.c
--- linux-2.4.16/fs/nfs/nfs3proc.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfs/nfs3proc.c	Fri Dec  7 19:34:54 2001
@@ -17,6 +17,37 @@
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
+/* A wrapper to handle the EJUKEBOX error message */
+static int
+nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
+{
+	sigset_t oldset;
+	int res;
+	rpc_clnt_sigmask(clnt, &oldset);
+	do {
+		res = rpc_call_sync(clnt, msg, flags);
+		if (res != -EJUKEBOX)
+			break;
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(NFS_JUKEBOX_RETRY_TIME);
+		res = -ERESTARTSYS;
+	} while (!signalled());
+	rpc_clnt_sigunmask(clnt, &oldset);
+	return res;
+}
+
+static inline int
+nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
+{
+	struct rpc_message msg = { proc, argp, resp, NULL };
+	return nfs3_rpc_wrapper(clnt, &msg, flags);
+}
+
+#define rpc_call(clnt, proc, argp, resp, flags) \
+		nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags)
+#define rpc_call_sync(clnt, msg, flags) \
+		nfs3_rpc_wrapper(clnt, msg, flags)
+
 /*
  * Bare-bones access to getattr: this is for nfs_read_super.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfs/pagelist.c linux/fs/nfs/pagelist.c
--- linux-2.4.16/fs/nfs/pagelist.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfs/pagelist.c	Fri Dec  7 19:36:53 2001
@@ -187,7 +187,7 @@
 		BUG();
 	}
 #endif
-	for (pos = head->prev; pos != head; pos = pos->prev) {
+	list_for_each_prev(pos, head) {
 		struct nfs_page	*p = nfs_list_entry(pos);
 		if (page_index(p->wb_page) < pg_idx)
 			break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfs/read.c linux/fs/nfs/read.c
--- linux-2.4.16/fs/nfs/read.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfs/read.c	Fri Dec  7 19:34:54 2001
@@ -402,6 +402,9 @@
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
 
+	if (nfs_async_handle_jukebox(task))
+		return;
+
 	nfs_refresh_inode(inode, &data->fattr);
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfs/unlink.c linux/fs/nfs/unlink.c
--- linux-2.4.16/fs/nfs/unlink.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfs/unlink.c	Fri Dec  7 19:34:54 2001
@@ -123,6 +123,8 @@
 	struct dentry		*dir = data->dir;
 	struct inode		*dir_i;
 
+	if (nfs_async_handle_jukebox(task))
+		return;
 	if (!dir)
 		return;
 	dir_i = dir->d_inode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfs/write.c linux/fs/nfs/write.c
--- linux-2.4.16/fs/nfs/write.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfs/write.c	Fri Dec  7 19:36:53 2001
@@ -305,18 +305,30 @@
 
 /*
  * Insert a write request into an inode
+ * Note: we sort the list in order to be able to optimize nfs_find_request()
+ *	 & co. for the 'write append' case. For 2.5 we may want to consider
+ *	 some form of hashing so as to perform well on random writes.
  */
 static inline void
 nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 {
+	struct list_head *pos, *head;
+	unsigned long pg_idx = page_index(req->wb_page);
+
 	if (!list_empty(&req->wb_hash))
 		return;
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
-	if (list_empty(&inode->u.nfs_i.writeback))
+	head = &inode->u.nfs_i.writeback;
+	if (list_empty(head))
 		igrab(inode);
+	list_for_each_prev(pos, head) {
+		struct nfs_page *entry = nfs_inode_wb_entry(pos);
+		if (page_index(entry->wb_page) < pg_idx)
+			break;
+	}
 	inode->u.nfs_i.npages++;
-	list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
+	list_add(&req->wb_hash, pos);
 	req->wb_count++;
 }
 
@@ -354,15 +366,18 @@
 static inline struct nfs_page *
 _nfs_find_request(struct inode *inode, struct page *page)
 {
-	struct list_head	*head, *next;
+	struct list_head	*head, *pos;
+	unsigned long pg_idx = page_index(page);
 
 	head = &inode->u.nfs_i.writeback;
-	next = head->next;
-	while (next != head) {
-		struct nfs_page *req = nfs_inode_wb_entry(next);
-		next = next->next;
-		if (page_index(req->wb_page) != page_index(page))
+	list_for_each_prev(pos, head) {
+		struct nfs_page *req = nfs_inode_wb_entry(pos);
+		unsigned long found_idx = page_index(req->wb_page);
+
+		if (pg_idx < found_idx)
 			continue;
+		if (pg_idx != found_idx)
+			break;
 		req->wb_count++;
 		return req;
 	}
@@ -444,20 +459,20 @@
 	else
 		idx_end = idx_start + npages - 1;
 
-	spin_lock(&nfs_wreq_lock);
 	head = &inode->u.nfs_i.writeback;
-	p = head->next;
-	while (p != head) {
+ restart:
+	spin_lock(&nfs_wreq_lock);
+	list_for_each_prev(p, head) {
 		unsigned long pg_idx;
 		struct nfs_page *req = nfs_inode_wb_entry(p);
 
-		p = p->next;
-
 		if (file && req->wb_file != file)
 			continue;
 
 		pg_idx = page_index(req->wb_page);
-		if (pg_idx < idx_start || pg_idx > idx_end)
+		if (pg_idx < idx_start)
+			break;
+		if (pg_idx > idx_end)
 			continue;
 
 		if (!NFS_WBACK_BUSY(req))
@@ -468,9 +483,8 @@
 		nfs_release_request(req);
 		if (error < 0)
 			return error;
-		spin_lock(&nfs_wreq_lock);
-		p = head->next;
 		res++;
+		goto restart;
 	}
 	spin_unlock(&nfs_wreq_lock);
 	return res;
@@ -991,6 +1005,9 @@
 	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
 		task->tk_pid, task->tk_status);
 
+	if (nfs_async_handle_jukebox(task))
+		return;
+
 	/* We can't handle that yet but we check for it nevertheless */
 	if (resp->count < argp->count && task->tk_status >= 0) {
 		static unsigned long    complain;
@@ -1183,6 +1200,9 @@
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
+
+	if (nfs_async_handle_jukebox(task))
+		return;
 
 	nfs_write_attributes(inode, resp->fattr);
 	while (!list_empty(&data->pages)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux-2.4.16/fs/nfsd/vfs.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nfsd/vfs.c	Tue Dec  4 19:25:31 2001
@@ -560,9 +560,13 @@
 		return NULL;
 	rap = frap;
 	ra = *frap;
-	memset(ra, 0, sizeof(*ra));
 	ra->p_dev = dev;
 	ra->p_ino = ino;
+	ra->p_reada = 0;
+	ra->p_ramax = 0;
+	ra->p_raend = 0;
+	ra->p_ralen = 0;
+	ra->p_rawin = 0;
 found:
 	if (rap != &raparm_cache) {
 		*rap = ra->p_next;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp1251.c linux/fs/nls/nls_cp1251.c
--- linux-2.4.16/fs/nls/nls_cp1251.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp1251.c	Tue Dec  4 19:25:31 2001
@@ -315,4 +315,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp1255.c linux/fs/nls/nls_cp1255.c
--- linux-2.4.16/fs/nls/nls_cp1255.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp1255.c	Tue Dec  4 19:25:31 2001
@@ -396,4 +396,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp437.c linux/fs/nls/nls_cp437.c
--- linux-2.4.16/fs/nls/nls_cp437.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp437.c	Tue Dec  4 19:25:31 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp737.c linux/fs/nls/nls_cp737.c
--- linux-2.4.16/fs/nls/nls_cp737.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp737.c	Tue Dec  4 19:25:31 2001
@@ -364,4 +364,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp775.c linux/fs/nls/nls_cp775.c
--- linux-2.4.16/fs/nls/nls_cp775.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp775.c	Tue Dec  4 19:25:31 2001
@@ -333,4 +333,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp850.c linux/fs/nls/nls_cp850.c
--- linux-2.4.16/fs/nls/nls_cp850.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp850.c	Tue Dec  4 19:25:31 2001
@@ -329,4 +329,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp852.c linux/fs/nls/nls_cp852.c
--- linux-2.4.16/fs/nls/nls_cp852.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp852.c	Tue Dec  4 19:25:31 2001
@@ -351,4 +351,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp855.c linux/fs/nls/nls_cp855.c
--- linux-2.4.16/fs/nls/nls_cp855.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp855.c	Tue Dec  4 19:25:31 2001
@@ -313,4 +313,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp857.c linux/fs/nls/nls_cp857.c
--- linux-2.4.16/fs/nls/nls_cp857.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp857.c	Tue Dec  4 19:25:31 2001
@@ -315,4 +315,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp860.c linux/fs/nls/nls_cp860.c
--- linux-2.4.16/fs/nls/nls_cp860.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp860.c	Tue Dec  4 19:25:31 2001
@@ -378,4 +378,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp861.c linux/fs/nls/nls_cp861.c
--- linux-2.4.16/fs/nls/nls_cp861.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp861.c	Tue Dec  4 19:25:31 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp862.c linux/fs/nls/nls_cp862.c
--- linux-2.4.16/fs/nls/nls_cp862.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp862.c	Tue Dec  4 19:25:31 2001
@@ -435,4 +435,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp863.c linux/fs/nls/nls_cp863.c
--- linux-2.4.16/fs/nls/nls_cp863.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp863.c	Tue Dec  4 19:25:31 2001
@@ -395,4 +395,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp864.c linux/fs/nls/nls_cp864.c
--- linux-2.4.16/fs/nls/nls_cp864.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp864.c	Tue Dec  4 19:25:31 2001
@@ -421,4 +421,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp865.c linux/fs/nls/nls_cp865.c
--- linux-2.4.16/fs/nls/nls_cp865.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp865.c	Tue Dec  4 19:25:31 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp866.c linux/fs/nls/nls_cp866.c
--- linux-2.4.16/fs/nls/nls_cp866.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp866.c	Tue Dec  4 19:25:31 2001
@@ -319,4 +319,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp869.c linux/fs/nls/nls_cp869.c
--- linux-2.4.16/fs/nls/nls_cp869.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp869.c	Tue Dec  4 19:25:31 2001
@@ -329,4 +329,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/nls/nls_cp874.c linux/fs/nls/nls_cp874.c
--- linux-2.4.16/fs/nls/nls_cp874.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/nls/nls_cp874.c	Tue Dec  4 19:25:31 2001
@@ -287,4 +287,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/openpromfs/inode.c linux/fs/openpromfs/inode.c
--- linux-2.4.16/fs/openpromfs/inode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/openpromfs/inode.c	Tue Dec  4 19:25:31 2001
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.14 2001/02/13 01:17:17 davem Exp $
+/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c
--- linux-2.4.16/fs/reiserfs/bitmap.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/bitmap.c	Thu Dec  6 16:25:59 2001
@@ -84,7 +84,7 @@
    to free a list of blocks at once. -Hans */
 				/* I wonder if it would be less modest
                                    now that we use journaling. -Hans */
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
+static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs;
@@ -92,9 +92,6 @@
     struct buffer_head ** apbh;
     int nr, offset;
 
-  RFALSE(!s, "vs-4060: trying to free block on nonexistent device");
-  RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block");
-
   PROC_INFO_INC( s, free_block );
 
   rs = SB_DISK_SUPER_BLOCK (s);
@@ -103,8 +100,12 @@
 
   get_bit_address (s, block, &nr, &offset);
 
-  /* mark it before we clear it, just in case */
-  journal_mark_freed(th, s, block) ;
+  if (nr >= sb_bmap_nr (rs)) {
+	  reiserfs_warning ("vs-4075: reiserfs_free_block: "
+			    "block %lu is out of range on %s\n", 
+			    block, bdevname(s->s_dev));
+	  return;
+  }
 
   reiserfs_prepare_for_journal(s, apbh[nr], 1 ) ;
 
@@ -124,7 +125,26 @@
   s->s_dirt = 1;
 }
 
+void reiserfs_free_block (struct reiserfs_transaction_handle *th, 
+                          unsigned long block) {
+    struct super_block * s = th->t_super;
+
+    RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
+    RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block");
+    /* mark it before we clear it, just in case */
+    journal_mark_freed(th, s, block) ;
+    _reiserfs_free_block(th, block) ;
+}
+
+/* preallocated blocks don't need to be run through journal_mark_freed */
+void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th, 
+                          unsigned long block) {
+    struct super_block * s = th->t_super;
 
+    RFALSE(!s, "vs-4060: trying to free block on nonexistent device");
+    RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block");
+    _reiserfs_free_block(th, block) ;
+}
 
 /* beginning from offset-th bit in bmap_nr-th bitmap block,
    find_forward finds the closest zero bit. It returns 1 and zero
@@ -402,7 +422,6 @@
     ** has allocated it.  loop around and try again
     */
     if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) {
-	reiserfs_warning("vs-4150: reiserfs_new_blocknrs, block not free");
 	reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ;
 	amount_needed++ ;
 	continue ;
@@ -488,12 +507,7 @@
     ** to be grouped towards the start of the border
     */
     border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
-  } else {
-    /* why would we want to delcare a local variable to this if statement
-    ** name border????? -chris
-    ** unsigned long border = 0;
-    */
-    if (!reiserfs_hashed_relocation(th->t_super)) {
+  } else if (!reiserfs_hashed_relocation(th->t_super)) {
       hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id);
 				/* I wonder if the CPU cost of the
                                    hash will obscure the layout
@@ -503,7 +517,6 @@
       
       hash_out = keyed_hash(((char *) (&hash_in)), 4);
       border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
-    }
   }
   border += bstart ;
   allocated[0] = 0 ; /* important.  Allows a check later on to see if at
@@ -659,11 +672,13 @@
 static void __discard_prealloc (struct reiserfs_transaction_handle * th,
 				struct inode * inode)
 {
+  unsigned long save = inode->u.reiserfs_i.i_prealloc_block ;
   while (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block);
+    reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block);
     inode->u.reiserfs_i.i_prealloc_block++;
     inode->u.reiserfs_i.i_prealloc_count --;
   }
+  inode->u.reiserfs_i.i_prealloc_block = save ; 
   list_del (&(inode->u.reiserfs_i.i_prealloc_list));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/buffer2.c linux/fs/reiserfs/buffer2.c
--- linux-2.4.16/fs/reiserfs/buffer2.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/buffer2.c	Thu Dec  6 16:21:36 2001
@@ -2,15 +2,6 @@
  *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README  
  */
 
-
-/*
- * Contains code from
- *
- *  linux/include/linux/lock.h and linux/fs/buffer.c /linux/fs/minix/fsync.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/locks.h>
@@ -21,12 +12,8 @@
 /*
  *  wait_buffer_until_released
  *  reiserfs_bread
- *  reiserfs_getblk
- *  get_new_buffer
  */
 
-
-
 /* when we allocate a new block (get_new_buffer, get_empty_nodes) and
    get buffer for it, it is possible that it is held by someone else
    or even by this process. In this function we wait until all other
@@ -47,7 +34,6 @@
     }
     run_task_queue(&tq_disk);
     current->policy |= SCHED_YIELD;
-    /*current->counter = 0;*/
     schedule();
   }
   if (repeat_counter > 30000000) {
@@ -63,7 +49,6 @@
    then it creates a new buffer and schedules I/O to read the
    block. */
 /* The function is NOT SCHEDULE-SAFE! */
-
 struct buffer_head  * reiserfs_bread (struct super_block *super, int n_block, int n_size) 
 {
     struct buffer_head  *result;
@@ -75,277 +60,4 @@
 	      PROC_INFO_INC( super, bread_miss ) );
     return result;
 }
-
-/* This function looks for a buffer which contains a given block.  If
-   the block is in cache it returns it, otherwise it returns a new
-   buffer which is not uptodate.  This is called by reiserfs_bread and
-   other functions. Note that get_new_buffer ought to be called this
-   and this ought to be called get_new_buffer, since this doesn't
-   actually get the block off of the disk. */
-/* The function is NOT SCHEDULE-SAFE! */
-
-struct buffer_head  * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size)
-{
-    return getblk (n_dev, n_block, n_size);
-}
-
-#ifdef NEW_GET_NEW_BUFFER
-
-/* returns one buffer with a blocknr near blocknr. */
-static int get_new_buffer_near_blocknr(
-                   struct super_block *  p_s_sb,
-                   int blocknr,
-                   struct buffer_head ** pp_s_new_bh,
-                   struct path         * p_s_path 
-                   ) {
-  unsigned      long n_new_blocknumber = 0;
-  int           n_ret_value,
-                n_repeat = CARRY_ON;
-
-#ifdef CONFIG_REISERFS_CHECK
-  int repeat_counter = 0;
-  
-  if (!blocknr)
-    printk ("blocknr passed to get_new_buffer_near_blocknr was 0");
-#endif
-
-
-  if ( (n_ret_value = reiserfs_new_blocknrs (p_s_sb, &n_new_blocknumber,
-                                             blocknr, 1)) == NO_DISK_SPACE )
-    return NO_DISK_SPACE;
-  
-  *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize);
-  if ( buffer_uptodate(*pp_s_new_bh) ) {
-
-    RFALSE( buffer_dirty(*pp_s_new_bh) || (*pp_s_new_bh)->b_dev == NODEV,
-	    "PAP-14080: invalid uptodate buffer %b for the new block", 
-	    *pp_s_new_bh);
-
-    /* Free path buffers to prevent deadlock. */
-    /* It is possible that this process has the buffer, which this function is getting, already in
-       its path, and is responsible for double incrementing the value of b_count.  If we recalculate
-       the path after schedule we can avoid risking an endless loop.  This problematic situation is
-       possible in a multiple processing environment.  Suppose process 1 has acquired a path P; then
-       process 2 balanced and remove block A from the tree.  Process 1 continues and runs
-       get_new_buffer, that returns buffer with block A. If node A was on the path P, then it will
-       have b_count == 2. If we now will simply wait in while ( (*pp_s_new_bh)->b_count > 1 ) we get
-       into an endless loop, as nobody will release this buffer and the current process holds buffer
-       twice. That is why we do decrement_counters_in_path(p_s_path) before waiting until b_count
-       becomes 1. (it there were other processes holding node A, then eventually we will get a
-       moment, when all of them released a buffer). */
-    if ( atomic_read (&((*pp_s_new_bh)->b_count)) > 1  ) {
-      decrement_counters_in_path(p_s_path);
-      n_ret_value |= SCHEDULE_OCCURRED;
-    }
-
-    while ( atomic_read (&((*pp_s_new_bh)->b_count)) > 1 ) {
-
-#ifdef REISERFS_INFO
-      printk("get_new_buffer() calls schedule to decrement b_count\n");
-#endif
-
-#ifdef CONFIG_REISERFS_CHECK
-      if ( ! (++repeat_counter % 10000) )
-	printk("get_new_buffer(%u): counter(%d) too big", current->pid, repeat_counter);
-#endif
-
-      current->counter = 0;
-      schedule();
-    }
-
-#ifdef CONFIG_REISERFS_CHECK
-    if ( buffer_dirty(*pp_s_new_bh) || (*pp_s_new_bh)->b_dev == NODEV ) {
-      print_buffer_head(*pp_s_new_bh,"get_new_buffer");
-      reiserfs_panic(p_s_sb, "PAP-14090: get_new_buffer: invalid uptodate buffer %b for the new block(case 2)", *pp_s_new_bh);
-    }
-#endif
-
-  }
-  else {
-    ;
-
-    RFALSE( atomic_read (&((*pp_s_new_bh)->b_count)) != 1,
-	    "PAP-14100: not uptodate buffer %b for the new block has b_count more than one",
-	    *pp_s_new_bh);
-
-  }
-  return (n_ret_value | n_repeat);
-}
-
-
-/* returns the block number of the last unformatted node, assumes p_s_key_to_search.k_offset is a byte in the tail of
-   the file, Useful for when you want to append to a file, and convert a direct item into an unformatted node near the
-   last unformatted node of the file.  Putting the unformatted node near the direct item is potentially very bad to do.
-   If there is no unformatted node in the file, then we return the block number of the direct item.  */
-/* The function is NOT SCHEDULE-SAFE! */
-inline int get_last_unformatted_node_blocknr_of_file(  struct key * p_s_key_to_search, struct super_block * p_s_sb,
-                                                       struct buffer_head * p_s_bh
-                                                       struct path * p_unf_search_path, struct inode * p_s_inode)
-
-{
-  struct key unf_key_to_search;
-  struct item_head * p_s_ih;
-  int n_pos_in_item;
-  struct buffer_head * p_indirect_item_bh;
-
-      copy_key(&unf_key_to_search,p_s_key_to_search);
-      unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
-      unf_key_to_search.k_offset = p_s_inode->u.reiserfs_i.i_first_direct_byte - 1;
-
-        /* p_s_key_to_search->k_offset -  MAX_ITEM_LEN(p_s_sb->s_blocksize); */
-      if (search_for_position_by_key (p_s_sb, &unf_key_to_search, p_unf_search_path, &n_pos_in_item) == POSITION_FOUND)
-        {
-          p_s_ih = B_N_PITEM_HEAD(p_indirect_item_bh = PATH_PLAST_BUFFER(p_unf_search_path), PATH_LAST_POSITION(p_unf_search_path));
-          return (B_I_POS_UNFM_POINTER(p_indirect_item_bh, p_s_ih, n_pos_in_item));
-        }
-     /*  else */
-      printk("reiser-1800: search for unformatted node failed, p_s_key_to_search->k_offset = %u,  unf_key_to_search.k_offset = %u, MAX_ITEM_LEN(p_s_sb->s_blocksize) = %ld, debug this\n", p_s_key_to_search->k_offset, unf_key_to_search.k_offset,  MAX_ITEM_LEN(p_s_sb->s_blocksize) );
-      print_buffer_head(PATH_PLAST_BUFFER(p_unf_search_path), "the buffer holding the item before the key we failed to find");
-      print_block_head(PATH_PLAST_BUFFER(p_unf_search_path), "the block head");
-      return 0;                         /* keeps the compiler quiet */
-}
-
-
-                                /* hasn't been out of disk space tested  */
-/* The function is NOT SCHEDULE-SAFE! */
-static int get_buffer_near_last_unf ( struct super_block * p_s_sb, struct key * p_s_key_to_search,
-                                                 struct inode *  p_s_inode,  struct buffer_head * p_s_bh, 
-                                                 struct buffer_head ** pp_s_un_bh, struct path * p_s_search_path)
-{
-  int unf_blocknr = 0, /* blocknr from which we start search for a free block for an unformatted node, if 0
-                          then we didn't find an unformatted node though we might have found a file hole */
-      n_repeat = CARRY_ON;
-  struct key unf_key_to_search;
-  struct path unf_search_path;
-
-  copy_key(&unf_key_to_search,p_s_key_to_search);
-  unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
-  
-  if (
-      (p_s_inode->u.reiserfs_i.i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
-                                                              crap other than what the name indicates, thus
-                                                              testing to see if it is 0 is not enough */
-      && (p_s_inode->u.reiserfs_i.i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
-                                                                           i_first_direct_byte = MAX_KEY_OFFSET */
-      )
-    {
-                                /* actually, we don't want the last unformatted node, we want the last unformatted node
-                                   which is before the current file offset */
-      unf_key_to_search.k_offset = ((p_s_inode->u.reiserfs_i.i_first_direct_byte -1) < unf_key_to_search.k_offset) ? p_s_inode->u.reiserfs_i.i_first_direct_byte -1 :  unf_key_to_search.k_offset;
-
-      while (unf_key_to_search.k_offset > -1)
-        {
-                                /* This is our poorly documented way of initializing paths. -Hans */
-          init_path (&unf_search_path);
-                                /* get the blocknr from which we start the search for a free block. */
-          unf_blocknr = get_last_unformatted_node_blocknr_of_file(  p_s_key_to_search, /* assumes this points to the file tail */
-                                                                    p_s_sb,     /* lets us figure out the block size */
-                                                                    p_s_bh, /* if there is no unformatted node in the file,
-                                                                               then it returns p_s_bh->b_blocknr */
-                                                                    &unf_search_path,
-                                                                    p_s_inode
-                                                                    );
-/*        printk("in while loop: unf_blocknr = %d,  *pp_s_un_bh = %p\n", unf_blocknr, *pp_s_un_bh); */
-          if (unf_blocknr) 
-            break;
-          else                  /* release the path and search again, this could be really slow for huge
-                                   holes.....better to spend the coding time adding compression though.... -Hans */
-            {
-                                /* Vladimir, is it a problem that I don't brelse these buffers ?-Hans */
-              decrement_counters_in_path(&unf_search_path);
-              unf_key_to_search.k_offset -= 4096;
-            }
-        }
-      if (unf_blocknr) {
-        n_repeat |= get_new_buffer_near_blocknr(p_s_sb, unf_blocknr, pp_s_un_bh, p_s_search_path);
-      }
-      else {                    /* all unformatted nodes are holes */
-        n_repeat |= get_new_buffer_near_blocknr(p_s_sb, p_s_bh->b_blocknr, pp_s_un_bh, p_s_search_path); 
-      }
-    }
-  else {                        /* file has no unformatted nodes */
-    n_repeat |= get_new_buffer_near_blocknr(p_s_sb, p_s_bh->b_blocknr, pp_s_un_bh, p_s_search_path);
-/*     printk("in else: unf_blocknr = %d,  *pp_s_un_bh = %p\n", unf_blocknr, *pp_s_un_bh); */
-/*     print_path (0,  p_s_search_path); */
-  }
-
-  return n_repeat;
-}
-
-#endif /* NEW_GET_NEW_BUFFER */
-
-
-#ifdef OLD_GET_NEW_BUFFER
-
-/* The function is NOT SCHEDULE-SAFE! */
-int get_new_buffer(
-		   struct reiserfs_transaction_handle *th, 
-		   struct buffer_head *  p_s_bh,
-		   struct buffer_head ** pp_s_new_bh,
-		   struct path	       * p_s_path
-		   ) {
-  unsigned	long n_new_blocknumber = 0;
-  int		n_repeat;
-  struct super_block *	 p_s_sb = th->t_super;
-
-  if ( (n_repeat = reiserfs_new_unf_blocknrs (th, &n_new_blocknumber, p_s_bh->b_blocknr)) == NO_DISK_SPACE )
-    return NO_DISK_SPACE;
-  
-  *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize);
-  if (atomic_read (&(*pp_s_new_bh)->b_count) > 1) {
-    /* Free path buffers to prevent deadlock which can occur in the
-       situation like : this process holds p_s_path; Block
-       (*pp_s_new_bh)->b_blocknr is on the path p_s_path, but it is
-       not necessary, that *pp_s_new_bh is in the tree; process 2
-       could remove it from the tree and freed block
-       (*pp_s_new_bh)->b_blocknr. Reiserfs_new_blocknrs in above
-       returns block (*pp_s_new_bh)->b_blocknr. Reiserfs_getblk gets
-       buffer for it, and it has b_count > 1. If we now will simply
-       wait in while ( (*pp_s_new_bh)->b_count > 1 ) we get into an
-       endless loop, as nobody will release this buffer and the
-       current process holds buffer twice. That is why we do
-       decrement_counters_in_path(p_s_path) before waiting until
-       b_count becomes 1. (it there were other processes holding node
-       pp_s_new_bh, then eventually we will get a moment, when all of
-       them released a buffer). */
-    decrement_counters_in_path(p_s_path);
-    wait_buffer_until_released (*pp_s_new_bh);
-    n_repeat |= SCHEDULE_OCCURRED;
-  }
-
-  RFALSE( atomic_read (&((*pp_s_new_bh)->b_count)) != 1 || 
-	  buffer_dirty (*pp_s_new_bh),
-	  "PAP-14100: not free or dirty buffer %b for the new block", 
-	  *pp_s_new_bh);
-
-  return n_repeat;
-}
-
-#endif /* OLD_GET_NEW_BUFFER */
-
-
-#ifdef GET_MANY_BLOCKNRS
-                                /* code not yet functional */
-get_next_blocknr (
-                  unsigned long *       p_blocknr_array,          /* we get a whole bunch of blocknrs all at once for
-                                                                     the write.  This is better than getting them one at
-                                                                     a time.  */
-                  unsigned long **      p_blocknr_index,        /* pointer to current offset into the array. */
-                  unsigned long        blocknr_array_length
-)
-{
-  unsigned long return_value;
-
-  if (*p_blocknr_index < p_blocknr_array + blocknr_array_length) {
-    return_value = **p_blocknr_index;
-    **p_blocknr_index = 0;
-    *p_blocknr_index++;
-    return (return_value);
-  }
-  else
-    {
-      kfree (p_blocknr_array);
-    }
-}
-#endif /* GET_MANY_BLOCKNRS */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/dir.c linux/fs/reiserfs/dir.c
--- linux-2.4.16/fs/reiserfs/dir.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/dir.c	Thu Dec  6 16:21:36 2001
@@ -22,22 +22,6 @@
     fsync:	reiserfs_dir_fsync,
 };
 
-/*
- * directories can handle most operations...
- */
-struct inode_operations reiserfs_dir_inode_operations = {
-  //&reiserfs_dir_operations,	/* default_file_ops */
-    create:	reiserfs_create,
-    lookup:	reiserfs_lookup,
-    link:	reiserfs_link,
-    unlink:	reiserfs_unlink,
-    symlink:	reiserfs_symlink,
-    mkdir:	reiserfs_mkdir,
-    rmdir:	reiserfs_rmdir,
-    mknod:	reiserfs_mknod,
-    rename:	reiserfs_rename,
-};
-
 int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
   lock_kernel();
   reiserfs_commit_for_inode(dentry->d_inode) ;
@@ -186,7 +170,7 @@
 	}
 	
 	/* directory continues in the right neighboring block */
-	set_cpu_key_k_offset (&pos_key, le_key_k_offset (ITEM_VERSION_1, rkey));
+	set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey));
 
     } /* while */
 
@@ -197,4 +181,72 @@
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
     return 0;
+}
+
+/* compose directory item containing "." and ".." entries (entries are
+   not aligned to 4 byte boundary) */
+/* the last four params are LE */
+void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+			     __u32 par_dirid, __u32 par_objid)
+{
+    struct reiserfs_de_head * deh;
+
+    memset (body, 0, EMPTY_DIR_SIZE_V1);
+    deh = (struct reiserfs_de_head *)body;
+    
+    /* direntry header of "." */
+    put_deh_offset( &(deh[0]), DOT_OFFSET );
+    /* these two are from make_le_item_head, and are are LE */
+    deh[0].deh_dir_id = dirid;
+    deh[0].deh_objectid = objid;
+    deh[0].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." ));
+    mark_de_visible(&(deh[0]));
+  
+    /* direntry header of ".." */
+    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET);
+    /* key of ".." for the root directory */
+    /* these two are from the inode, and are are LE */
+    deh[1].deh_dir_id = par_dirid;
+    deh[1].deh_objectid = par_objid;
+    deh[1].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) );
+    mark_de_visible(&(deh[1]));
+
+    /* copy ".." and "." */
+    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
+    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
+}
+
+/* compose directory item containing "." and ".." entries */
+void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+			  __u32 par_dirid, __u32 par_objid)
+{
+    struct reiserfs_de_head * deh;
+
+    memset (body, 0, EMPTY_DIR_SIZE);
+    deh = (struct reiserfs_de_head *)body;
+    
+    /* direntry header of "." */
+    put_deh_offset( &(deh[0]), DOT_OFFSET );
+    /* these two are from make_le_item_head, and are are LE */
+    deh[0].deh_dir_id = dirid;
+    deh[0].deh_objectid = objid;
+    deh[0].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) );
+    mark_de_visible(&(deh[0]));
+  
+    /* direntry header of ".." */
+    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET );
+    /* key of ".." for the root directory */
+    /* these two are from the inode, and are are LE */
+    deh[1].deh_dir_id = par_dirid;
+    deh[1].deh_objectid = par_objid;
+    deh[1].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) );
+    mark_de_visible(&(deh[1]));
+
+    /* copy ".." and "." */
+    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
+    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/do_balan.c linux/fs/reiserfs/do_balan.c
--- linux-2.4.16/fs/reiserfs/do_balan.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/do_balan.c	Thu Dec  6 16:21:36 2001
@@ -274,13 +274,6 @@
     int pos_in_item;
     int zeros_num;
 
-#if 0
-    if (tb->insert_size [0] % 4) {
-	reiserfs_panic (tb->tb_sb, "balance_leaf: wrong insert_size %d", 
-			tb->insert_size [0]);
-    }
-#endif
-
     PROC_INFO_INC( tb -> tb_sb, balance_at[ 0 ] );
 
     /* Make balance in case insert_size[0] < 0 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/file.c linux/fs/reiserfs/file.c
--- linux-2.4.16/fs/reiserfs/file.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/file.c	Thu Dec  6 16:21:36 2001
@@ -33,7 +33,7 @@
 
     /* fast out for when nothing needs to be done */
     if ((atomic_read(&inode->i_count) > 1 ||
-         !inode->u.reiserfs_i.i_pack_on_close || 
+         !(inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) || 
          !tail_has_to_be_packed(inode))       && 
 	inode->u.reiserfs_i.i_prealloc_count <= 0) {
 	return 0;
@@ -50,7 +50,7 @@
     journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
 
     if (atomic_read(&inode->i_count) <= 1 &&
-	inode->u.reiserfs_i.i_pack_on_close &&
+	(inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) &&
         tail_has_to_be_packed (inode)) {
 	/* if regular file is released by last holder and it has been
 	   appended (we append by unformatted node only) or its direct
@@ -97,10 +97,16 @@
 	/* version 2 items will be caught by the s_maxbytes check
 	** done for us in vmtruncate
 	*/
-        if (inode_items_version(inode) == ITEM_VERSION_1 && 
+	if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
 	    attr->ia_size > MAX_NON_LFS)
             return -EFBIG ;
     }
+
+    if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) ||
+	 ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) &&
+	(get_inode_sd_version (inode) == STAT_DATA_V1))
+		/* stat data of format v3.5 has 16 bit uid and gid */
+	    return -EINVAL;
 
     error = inode_change_ok(inode, attr) ;
     if (!error)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- linux-2.4.16/fs/reiserfs/fix_node.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/fix_node.c	Thu Dec  6 16:21:36 2001
@@ -806,7 +806,7 @@
     RFALSE( ! *p_n_blocknr,
 	    "PAP-8135: reiserfs_new_blocknrs failed when got new blocks");
 
-    p_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, *p_n_blocknr, p_s_sb->s_blocksize);
+    p_s_new_bh = getblk(p_s_sb->s_dev, *p_n_blocknr, p_s_sb->s_blocksize);
     if (atomic_read (&(p_s_new_bh->b_count)) > 1) {
 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
 /*
@@ -2021,23 +2021,6 @@
   // entry would eat 2 byte of virtual node space
   return sb->s_blocksize;
 
-#if 0
-  size = sizeof (struct virtual_node) + sizeof (struct virtual_item);
-  ih = B_N_PITEM_HEAD (bh, 0);
-  nr_items = B_NR_ITEMS (bh);
-  for (i = 0; i < nr_items; i ++, ih ++) {
-    /* each item occupies some space in virtual node */
-    size += sizeof (struct virtual_item);
-    if (is_direntry_le_ih (ih))
-      /* each entry and new one occupeis 2 byte in the virtual node */
-      size += (ih_entry_count(ih) + 1) * sizeof( __u16 );
-  }
-  
-  /* 1 bit for each bitmap block to note whether bitmap block was
-     dirtied in the operation */
- /* size += (SB_BMAP_NR (sb) * 2 / 8 + 4);*/
-  return size;
-#endif
 }
 
 
@@ -2342,15 +2325,6 @@
 	reiserfs_panic (p_s_tb->tb_sb, "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate "
 			"at the beginning of fix_nodes or not in tree (mode %c)", p_s_tbS0, p_s_tbS0, n_op_mode);
     }
-
-    // FIXME: new items have to be of 8 byte multiples. Including new
-    // directory items those look like old ones
-    /*
-    if (p_s_tb->insert_size[0] % 8)
-	reiserfs_panic (p_s_tb->tb_sb, "vs-: fix_nodes: incorrect insert_size %d, "
-			"mode %c",
-			p_s_tb->insert_size[0], n_op_mode);
-    */
 
     /* Check parameters. */
     switch (n_op_mode) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- linux-2.4.16/fs/reiserfs/inode.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/inode.c	Thu Dec  6 16:21:36 2001
@@ -17,6 +17,8 @@
 #define GET_BLOCK_READ_DIRECT 4  /* read the tail if indirect item not found */
 #define GET_BLOCK_NO_ISEM     8 /* i_sem is not held, don't preallocate */
 
+static int reiserfs_get_block (struct inode * inode, long block,
+			       struct buffer_head * bh_result, int create);
 //
 // initially this function was derived from minix or ext2's analog and
 // evolved as the prototype did
@@ -40,11 +42,13 @@
 
 	reiserfs_delete_object (&th, inode);
 	pop_journal_writer(windex) ;
-	reiserfs_release_objectid (&th, inode->i_ino);
 
 	journal_end(&th, inode->i_sb, jbegin_count) ;
 
-	up (&inode->i_sem); 
+        up (&inode->i_sem);
+
+        /* all items of file are deleted, so we can remove "save" link */
+	remove_save_link (inode, 0/* not truncate */);
     } else {
 	/* no object items are in the tree */
 	;
@@ -72,9 +76,9 @@
 void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
 	      int type, int length )
 {
-  _make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
-	  	   le32_to_cpu (INODE_PKEY (inode)->k_objectid), 
-		   offset, type, length);
+  _make_cpu_key (key, get_inode_item_key_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
+		 le32_to_cpu (INODE_PKEY (inode)->k_objectid), 
+		 offset, type, length);
 }
 
 
@@ -215,9 +219,9 @@
 // files which were created in the earlier version can not be longer,
 // than 2 gb
 //
-int file_capable (struct inode * inode, long block)
+static int file_capable (struct inode * inode, long block)
 {
-    if (inode_items_version (inode) != ITEM_VERSION_1 || // it is new file.
+    if (get_inode_item_key_version (inode) != KEY_FORMAT_3_5 || // it is new file.
 	block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb
 	return 1;
 
@@ -511,8 +515,8 @@
 // determine which parts are derivative, if any, understanding that
 // there are only so many ways to code to a given interface.
 //
-int reiserfs_get_block (struct inode * inode, long block,
-			struct buffer_head * bh_result, int create)
+static int reiserfs_get_block (struct inode * inode, long block,
+			       struct buffer_head * bh_result, int create)
 {
     int repeat, retval;
     unsigned long tag;
@@ -540,7 +544,7 @@
 				/* bad.... */
     lock_kernel() ;
     th.t_trans_id = 0 ;
-    version = inode_items_version (inode);
+    version = get_inode_item_key_version (inode);
 
     if (block < 0) {
 	unlock_kernel();
@@ -564,7 +568,7 @@
 	return ret;
     }
 
-    inode->u.reiserfs_i.i_pack_on_close = 1 ;
+    inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask;
 
     windex = push_journal_writer("reiserfs_get_block") ;
   
@@ -880,7 +884,8 @@
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
 	unsigned long blocks;
 
-	inode_items_version (inode) = ITEM_VERSION_1;
+	set_inode_item_key_version (inode, KEY_FORMAT_3_5);
+        set_inode_sd_version (inode, STAT_DATA_V1);
 	inode->i_mode  = sd_v1_mode(sd);
 	inode->i_nlink = sd_v1_nlink(sd);
 	inode->i_uid   = sd_v1_uid(sd);
@@ -929,13 +934,13 @@
             inode->i_generation = sd_v2_generation(sd);
 
 	if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode))
-	    inode_items_version (inode) = ITEM_VERSION_1;
+	    set_inode_item_key_version (inode, KEY_FORMAT_3_5);
 	else
-	    inode_items_version (inode) = ITEM_VERSION_2;
+            set_inode_item_key_version (inode, KEY_FORMAT_3_6);
     }
 
     /* nopack = 0, by default */
-    inode->u.reiserfs_i.nopack = 0;
+    inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
 
     pathrelse (path);
     if (S_ISREG (inode->i_mode)) {
@@ -1115,7 +1120,7 @@
 
     /* set version 1, version 2 could be used too, because stat data
        key is the same in both versions */
-    key.version = ITEM_VERSION_1;
+    key.version = KEY_FORMAT_3_5;
     key.on_disk_key.k_dir_id = dirino;
     key.on_disk_key.k_objectid = inode->i_ino;
     key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET;
@@ -1138,6 +1143,30 @@
     }
 
     init_inode (inode, &path_to_sd);
+   
+    /* It is possible that knfsd is trying to access inode of a file
+       that is being removed from the disk by some other thread. As we
+       update sd on unlink all that is required is to check for nlink
+       here. This bug was first found by Sizif when debugging
+       SquidNG/Butterfly, forgotten, and found again after Philippe
+       Gramoulle <philippe.gramoulle@mmania.com> reproduced it. 
+
+       More logical fix would require changes in fs/inode.c:iput() to
+       remove inode from hash-table _after_ fs cleaned disk stuff up and
+       in iget() to return NULL if I_FREEING inode is found in
+       hash-table. */
+    /* Currently there is one place where it's ok to meet inode with
+       nlink==0: processing of open-unlinked and half-truncated files
+       during mount (fs/reiserfs/super.c:finish_unfinished()). */
+    if( ( inode -> i_nlink == 0 ) && 
+	! inode -> i_sb -> u.reiserfs_sb.s_is_unlinked_ok ) {
+	    reiserfs_warning( "vs-13075: reiserfs_read_inode2: "
+			      "dead inode read from disk %K. "
+			      "This is likely to be race with knfsd. Ignore\n", 
+			      &key );
+	    make_bad_inode( inode );
+    }
+
     reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */
 
 }
@@ -1162,7 +1191,7 @@
 }
 
 struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data,
-                                     int len, int fhtype, int parent) {
+				     int len, int fhtype, int parent) {
     struct cpu_key key ;
     struct inode *inode = NULL ;
     struct list_head *lp;
@@ -1303,26 +1332,6 @@
     }
 }
 
-void reiserfs_dirty_inode (struct inode * inode) {
-    struct reiserfs_transaction_handle th ;
-
-    if (inode->i_sb->s_flags & MS_RDONLY) {
-        reiserfs_warning("clm-6006: writing inode %lu on readonly FS\n", 
-	                  inode->i_ino) ;
-        return ;
-    }
-    lock_kernel() ;
-
-    /* this is really only used for atime updates, so they don't have
-    ** to be included in O_SYNC or fsync
-    */
-    journal_begin(&th, inode->i_sb, 1) ;
-    reiserfs_update_sd (&th, inode);
-    journal_end(&th, inode->i_sb, 1) ;
-    unlock_kernel() ;
-}
-
-
 /* FIXME: no need any more. right? */
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode)
 {
@@ -1345,20 +1354,20 @@
     struct cpu_key key;
     int retval;
     
-    _make_cpu_key (&key, ITEM_VERSION_1, le32_to_cpu (ih->ih_key.k_dir_id),
+    _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id),
 		   le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/);
     
     /* compose item head for new item. Directories consist of items of
        old type (ITEM_VERSION_1). Do not set key (second arg is 0), it
        is done by reiserfs_new_inode */
     if (old_format_only (sb)) {
-	make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
+	make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
 	
 	make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
 				INODE_PKEY (dir)->k_dir_id, 
 				INODE_PKEY (dir)->k_objectid );
     } else {
-	make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
+	make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
 	
 	make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
 		   		INODE_PKEY (dir)->k_dir_id, 
@@ -1394,12 +1403,12 @@
     struct cpu_key key;
     int retval;
 
-    _make_cpu_key (&key, ITEM_VERSION_1, 
+    _make_cpu_key (&key, KEY_FORMAT_3_5, 
 		   le32_to_cpu (ih->ih_key.k_dir_id), 
 		   le32_to_cpu (ih->ih_key.k_objectid),
 		   1, TYPE_DIRECT, 3/*key length*/);
 
-    make_le_item_head (ih, 0, ITEM_VERSION_1, 1, TYPE_DIRECT, item_len, 0/*free_space*/);
+    make_le_item_head (ih, 0, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/);
 
     /* look for place in the tree for new item */
     retval = search_item (sb, &key, path);
@@ -1470,13 +1479,13 @@
       inode->i_generation = ++event;
 #endif
     if (old_format_only (sb))
-	make_le_item_head (&ih, 0, ITEM_VERSION_1, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
+	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, ITEM_VERSION_2, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
+	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, ITEM_VERSION_2, le32_to_cpu (ih.ih_key.k_dir_id),
+    _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*/);
 
     /* find proper place for inserting of stat data */
@@ -1512,9 +1521,16 @@
 
     INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
 
-    if (old_format_only (sb))
+    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;
+	}
 	inode2sd_v1 (&sd, inode);
-    else
+    } else
 	inode2sd (&sd, inode);
 
     // these do not go to on-disk stat data
@@ -1527,10 +1543,14 @@
     // format, other new objects will consist of new items)
     memcpy (INODE_PKEY (inode), &(ih.ih_key), KEY_SIZE);
     if (old_format_only (sb) || S_ISDIR(mode) || S_ISLNK(mode))
-	inode_items_version (inode) = ITEM_VERSION_1;
+        set_inode_item_key_version (inode, KEY_FORMAT_3_5);
     else
-	inode_items_version (inode) = ITEM_VERSION_2;
-
+        set_inode_item_key_version (inode, KEY_FORMAT_3_6);
+    if (old_format_only (sb))
+	set_inode_sd_version (inode, STAT_DATA_V1);
+    else
+	set_inode_sd_version (inode, STAT_DATA_V2);
+    
     /* insert the stat data into the tree */
     retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
     if (retval) {
@@ -1690,12 +1710,23 @@
     ** because the truncate might pack the item anyway 
     ** (it will unmap bh if it packs).
     */
-    journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
+    /* it is enough to reserve space in transaction for 2 balancings:
+       one for "save" link adding and another for the first
+       cut_from_item. 1 is for update_sd */
+    journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
     reiserfs_update_inode_transaction(p_s_inode) ;
     windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
+    if (update_timestamps)
+           /* we are doing real truncate: if the system crashes before the last
+              transaction of truncating gets committed - on reboot the file
+              either appears truncated properly or not truncated at all */
+           add_save_link (&th, p_s_inode, 1);
     reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
     pop_journal_writer(windex) ;
-    journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
+    journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+
+    if (update_timestamps)
+       remove_save_link (p_s_inode, 1/* truncate */);
 
     if (page) {
         length = offset & (blocksize - 1) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/ioctl.c linux/fs/reiserfs/ioctl.c
--- linux-2.4.16/fs/reiserfs/ioctl.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/ioctl.c	Thu Dec  6 16:21:36 2001
@@ -46,7 +46,7 @@
         return -EINVAL ;
     }
     /* ioctl already done */
-    if (inode->u.reiserfs_i.nopack) {
+    if (inode->u.reiserfs_i.i_flags & i_nopack_mask) {
         return 0 ;
     }
     lock_kernel();
@@ -59,7 +59,7 @@
     write_from = inode->i_size & (blocksize - 1) ;
     /* if we are on a block boundary, we are already unpacked.  */
     if ( write_from == 0) {
-	inode->u.reiserfs_i.nopack = 1;
+	inode->u.reiserfs_i.i_flags |= i_nopack_mask;
 	goto out ;
     }
 
@@ -79,7 +79,7 @@
 
     /* conversion can change page contents, must flush */
     flush_dcache_page(page) ;
-    inode->u.reiserfs_i.nopack = 1;
+    inode->u.reiserfs_i.i_flags |= i_nopack_mask;
     kunmap(page) ; /* mapped by prepare_write */
 
 out_unlock:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- linux-2.4.16/fs/reiserfs/journal.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/journal.c	Thu Dec  6 16:21:36 2001
@@ -92,6 +92,8 @@
 static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;
 static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall)  ;
 static int can_dirty(struct reiserfs_journal_cnode *cn) ;
+static int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed);
+static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks);
 
 static void init_journal_hash(struct super_block *p_s_sb) {
   memset(SB_JOURNAL(p_s_sb)->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;
@@ -147,7 +149,7 @@
   }
   bn = allocate_bitmap_node(p_s_sb) ;
   if (!bn) {
-    current->policy = SCHED_YIELD ;
+    current->policy |= SCHED_YIELD ;
     schedule() ;
     goto repeat ;
   }
@@ -1697,7 +1699,7 @@
   /* step three, starting at the oldest transaction, replay */
   if (last_flush_start > 0) {
     oldest_start = last_flush_start ;
-    oldest_trans_id = last_flush_trans_id ;
+    oldest_trans_id = last_flush_trans_id + 1 ;
   } 
   cur_dblock = oldest_start ;
   if (oldest_trans_id)  {
@@ -1717,6 +1719,8 @@
     }
     cur_dblock = reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start ;
     replay_count++ ;
+   if (cur_dblock == oldest_start)
+        break;
   }
 
   if (oldest_trans_id == 0) {
@@ -2083,7 +2087,7 @@
 }
 
 
-int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
+static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
   return do_journal_begin_r(th, p_s_sb, nblocks, 1) ;
 }
 
@@ -2238,7 +2242,7 @@
 **
 ** returns 1 if it cleaned and relsed the buffer. 0 otherwise
 */
-int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) {
+static int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) {
   struct buffer_head *bh ;
   struct reiserfs_journal_cnode *cn ;
   int ret = 0;
@@ -2279,7 +2283,7 @@
 }
 
 /* removes from a specific journal list hash */
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
+static int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
   remove_journal_hash(SB_JOURNAL(s)->j_list_hash_table, jl, bh, remove_freed) ;
   return 0 ;
 }
@@ -2341,20 +2345,6 @@
 int show_reiserfs_locks(void) {
 
   dump_journal_writers() ;
-#if 0 /* debugging code for when we are compiled static don't delete */
-  p_s_sb = sb_entry(super_blocks.next);
-  while (p_s_sb != sb_entry(&super_blocks)) {
-    if (reiserfs_is_super(p_s_sb)) {
-printk("journal lock is %d, join lock is %d, writers %d must wait is %d\n", 
-        atomic_read(&(SB_JOURNAL(p_s_sb)->j_wlock)),
-        atomic_read(&(SB_JOURNAL(p_s_sb)->j_jlock)),
-	atomic_read(&(SB_JOURNAL(p_s_sb)->j_wcount)),
-	SB_JOURNAL(p_s_sb)->j_must_wait) ;
-	printk("used cnodes %d, free cnodes %d\n", SB_JOURNAL(p_s_sb)->j_cnode_used, SB_JOURNAL(p_s_sb)->j_cnode_free) ;
-    }
-    p_s_sb = sb_entry(p_s_sb->s_list.next);
-  }
-#endif
   return 0 ;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/lbalance.c linux/fs/reiserfs/lbalance.c
--- linux-2.4.16/fs/reiserfs/lbalance.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/lbalance.c	Thu Dec  6 16:21:36 2001
@@ -63,7 +63,7 @@
 
 	/* form item header */
 	memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
-	put_ih_version( &new_ih, ITEM_VERSION_1 );
+	put_ih_version( &new_ih, KEY_FORMAT_3_5 );
 	/* calculate item len */
 	put_ih_item_len( &new_ih, DEH_SIZE * copy_count + copy_records_len );
 	put_ih_entry_count( &new_ih, 0 );
@@ -78,7 +78,7 @@
 		set_le_ih_k_offset (&new_ih, U32_MAX);
 		/* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
 	    }
-	    set_le_key_k_type (ITEM_VERSION_1, &(new_ih.ih_key), TYPE_DIRENTRY);
+	    set_le_key_k_type (KEY_FORMAT_3_5, &(new_ih.ih_key), TYPE_DIRENTRY);
 	}
     
 	/* insert item into dest buffer */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c
--- linux-2.4.16/fs/reiserfs/namei.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/namei.c	Thu Dec  6 16:21:36 2001
@@ -17,17 +17,6 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 
-				/* there should be an overview right
-                                   here, as there should be in every
-                                   conceptual grouping of code.  This
-                                   should be combined with dir.c and
-                                   called dir.c (naming will become
-                                   too large to be called one file in
-                                   a few years), stop senselessly
-                                   imitating the incoherent
-                                   structuring of code used by other
-                                   filesystems.  */
-
 #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
 #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
 
@@ -105,7 +94,7 @@
 	BUG ();
 
     /* store key of the found entry */
-    de->de_entry_key.version = ITEM_VERSION_1;
+    de->de_entry_key.version = KEY_FORMAT_3_5;
     de->de_entry_key.on_disk_key.k_dir_id = le32_to_cpu (de->de_ih->ih_key.k_dir_id);
     de->de_entry_key.on_disk_key.k_objectid = le32_to_cpu (de->de_ih->ih_key.k_objectid);
     set_cpu_key_k_offset (&(de->de_entry_key), deh_offset (deh));
@@ -347,7 +336,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry)
+static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry)
 {
     int retval;
     struct inode * inode = 0;
@@ -373,7 +362,6 @@
     return NULL;
 }
 
-
 //
 // a portion of this function, particularly the VFS interface portion,
 // was derived from minix or ext2's analog and evolved as the
@@ -518,7 +506,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
+static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
     struct inode * inode;
@@ -574,7 +562,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
     int retval;
     struct inode * inode;
@@ -629,7 +617,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
+static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
     struct inode * inode;
@@ -708,17 +696,20 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
+static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
 {
     int retval;
     struct inode * inode;
     int windex ;
     struct reiserfs_transaction_handle th ;
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+    int jbegin_count; 
     INITIALIZE_PATH (path);
     struct reiserfs_dir_entry de;
 
 
+    /* we will be doing 2 balancings and update 2 stat data */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
     windex = push_journal_writer("reiserfs_rmdir") ;
 
@@ -762,6 +753,9 @@
     dir->i_blocks = ((dir->i_size + 511) >> 9);
     reiserfs_update_sd (&th, dir);
 
+    /* prevent empty directory from getting lost */
+    add_save_link (&th, inode, 0/* not truncate */);
+
     pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_check_path(&path) ;
@@ -785,7 +779,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
+static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
 {
     int retval;
     struct inode * inode;
@@ -793,7 +787,13 @@
     INITIALIZE_PATH (path);
     int windex ;
     struct reiserfs_transaction_handle th ;
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+    int jbegin_count;
+
+    inode = dentry->d_inode;
+
+    /* in this transaction we can be doing at max two balancings and update
+       two stat datas */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
 
     journal_begin(&th, dir->i_sb, jbegin_count) ;
     windex = push_journal_writer("reiserfs_unlink") ;
@@ -803,7 +803,6 @@
 	retval = -ENOENT;
 	goto end_unlink;
     }
-    inode = dentry->d_inode;
 
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
@@ -834,6 +833,10 @@
     dir->i_ctime = dir->i_mtime = CURRENT_TIME;
     reiserfs_update_sd (&th, dir);
 
+    if (!inode->i_nlink)
+       /* prevent file from getting lost */
+       add_save_link (&th, inode, 0/* not truncate */);
+
     pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_check_path(&path) ;
@@ -855,7 +858,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_symlink (struct inode * dir, struct dentry * dentry, const char * symname)
+static int reiserfs_symlink (struct inode * dir, struct dentry * dentry, const char * symname)
 {
     int retval;
     struct inode * inode;
@@ -932,7 +935,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry)
+static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry)
 {
     int retval;
     struct inode *inode = old_dentry->d_inode;
@@ -1032,8 +1035,8 @@
  * one path. If it holds 2 or more, it can get into endless waiting in
  * get_empty_nodes or its clones 
  */
-int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
-		     struct inode * new_dir, struct dentry *new_dentry)
+static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
+			    struct inode * new_dir, struct dentry *new_dentry)
 {
     int retval;
     INITIALIZE_PATH (old_entry_path);
@@ -1044,8 +1047,13 @@
     struct inode * old_inode, * new_inode;
     int windex ;
     struct reiserfs_transaction_handle th ;
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+    int jbegin_count ; 
+
 
+    /* two balancings: old name removal, new name insertion or "save" link,
+       stat data updates: old directory and new directory and maybe block
+       containing ".." of renamed directory */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 3;
 
     old_inode = old_dentry->d_inode;
     new_inode = new_dentry->d_inode;
@@ -1096,8 +1104,8 @@
 	// FIXME: is it possible, that new_inode == 0 here? If yes, it
 	// is not clear how does ext2 handle that
 	if (!new_inode) {
-	    printk ("reiserfs_rename: new entry is found, new inode == 0\n");
-	    BUG ();
+	    reiserfs_panic (old_dir->i_sb,
+			    "vs-7050: new entry is found, new inode == 0\n");
 	}
     } else if (retval) {
 	pop_journal_writer(windex) ;
@@ -1164,13 +1172,6 @@
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
 	    if (S_ISDIR(old_inode->i_mode))
 		reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
-#if 0
-	    // FIXME: do we need this? shouldn't we simply continue?
-	    run_task_queue(&tq_disk);
-	    current->policy |= SCHED_YIELD;
-	    /*current->counter = 0;*/
-	    schedule();
-#endif
 	    continue;
 	}
 
@@ -1195,29 +1196,25 @@
     if (new_inode) {
 	// adjust link number of the victim
 	if (S_ISDIR(new_inode->i_mode)) {
-	  DEC_DIR_INODE_NLINK(new_inode)
+	    new_inode->i_nlink  = 0;
 	} else {
-	  new_inode->i_nlink--;
+	    new_inode->i_nlink--;
 	}
 	new_inode->i_ctime = CURRENT_TIME;
     }
 
     if (S_ISDIR(old_inode->i_mode)) {
-      //if (dot_dot_de.de_bh) {
-	// adjust ".." of renamed directory
+	// adjust ".." of renamed directory 
 	set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
 	journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh);
-
-	DEC_DIR_INODE_NLINK(old_dir)
-	if (new_inode) {
-	    if (S_ISDIR(new_inode->i_mode)) {
-		DEC_DIR_INODE_NLINK(new_inode)
-	    } else {
-	        new_inode->i_nlink--;
-	    }
-	} else {
-	    INC_DIR_INODE_NLINK(new_dir)
-	}
+	
+        if (!new_inode)
+	    /* there (in new_dir) was no directory, so it got new link
+	       (".."  of renamed directory) */
+	    INC_DIR_INODE_NLINK(new_dir);
+		
+	/* old directory lost one link - ".. " of renamed directory */
+	DEC_DIR_INODE_NLINK(old_dir);
     }
 
     // looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse
@@ -1228,18 +1225,40 @@
     // anybody, but it will panic if will not be able to find the
     // entry. This needs one more clean up
     if (reiserfs_cut_from_item (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL, 0) < 0)
-	reiserfs_warning ("vs-: reiserfs_rename: coudl not cut old name. Fsck later?\n");
+	reiserfs_warning ("vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?\n");
 
     old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
     old_dir->i_blocks = ((old_dir->i_size + 511) >> 9);
 
     reiserfs_update_sd (&th, old_dir);
     reiserfs_update_sd (&th, new_dir);
-    if (new_inode)
+
+    if (new_inode) {
+	if (new_inode->i_nlink == 0)
+	    add_save_link (&th, new_inode, 0/* not truncate */);
 	reiserfs_update_sd (&th, new_inode);
+    }
 
     pop_journal_writer(windex) ;
     journal_end(&th, old_dir->i_sb, jbegin_count) ;
     return 0;
 }
+
+
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations reiserfs_dir_inode_operations = {
+  //&reiserfs_dir_operations,	/* default_file_ops */
+    create:	reiserfs_create,
+    lookup:	reiserfs_lookup,
+    link:	reiserfs_link,
+    unlink:	reiserfs_unlink,
+    symlink:	reiserfs_symlink,
+    mkdir:	reiserfs_mkdir,
+    rmdir:	reiserfs_rmdir,
+    mknod:	reiserfs_mknod,
+    rename:	reiserfs_rename,
+};
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/objectid.c linux/fs/reiserfs/objectid.c
--- linux-2.4.16/fs/reiserfs/objectid.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/objectid.c	Thu Dec  6 16:21:36 2001
@@ -162,7 +162,7 @@
 	i += 2;
     }
 
-    reiserfs_warning ("vs-15010: reiserfs_release_objectid: tried to free free object id (%lu)", 
+    reiserfs_warning ("vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)\n", 
 		      ( long unsigned ) objectid_to_release);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/prints.c linux/fs/reiserfs/prints.c
--- linux-2.4.16/fs/reiserfs/prints.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/prints.c	Thu Dec  6 16:21:36 2001
@@ -109,7 +109,7 @@
 static void sprintf_item_head (char * buf, struct item_head * ih)
 {
     if (ih) {
-	sprintf (buf, "%s", (ih_version (ih) == ITEM_VERSION_2) ? "*NEW* " : "*OLD*");
+	sprintf (buf, "%s", (ih_version (ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*");
 	sprintf_le_key (buf + strlen (buf), &(ih->ih_key));
 	sprintf (buf + strlen (buf), ", item_len %d, item_location %d, "
 		 "free_space(entry_count) %d",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/resize.c linux/fs/reiserfs/resize.c
--- linux-2.4.16/fs/reiserfs/resize.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/resize.c	Thu Dec  6 16:21:36 2001
@@ -111,7 +111,7 @@
 	    for (i = 0; i < bmap_nr; i++)
 		bitmap[i] = SB_AP_BITMAP(s)[i];
 	    for (i = bmap_nr; i < bmap_nr_new; i++) {
-		bitmap[i] = reiserfs_getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize);
+		bitmap[i] = getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize);
 		memset(bitmap[i]->b_data, 0, sb->s_blocksize);
 		reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- linux-2.4.16/fs/reiserfs/stree.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/stree.c	Thu Dec  6 16:21:36 2001
@@ -225,7 +225,7 @@
     
     // find out version of the key
     to->version = le_key_version (from);
-    if (to->version == ITEM_VERSION_1) {
+    if (to->version == KEY_FORMAT_3_5) {
 	to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset);
 	to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness);
     } else {
@@ -604,7 +604,7 @@
     if (blocknr == 0)
 	return;
 
-    bh = reiserfs_getblk (s->s_dev, blocknr, s->s_blocksize);
+    bh = getblk (s->s_dev, blocknr, s->s_blocksize);
   
     if (!buffer_uptodate (bh)) {
 	ll_rw_block (READA, 1, &bh);
@@ -727,7 +727,11 @@
 	    continue;
 	}
 
-	RFALSE( ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
+        /* only check that the key is in the buffer if p_s_key is not
+           equal to the MAX_KEY. Latter case is only possible in
+           "finish_unfinished()" processing during mount. */
+        RFALSE( COMP_KEYS( &MAX_KEY, p_s_key ) && 
+                ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
 		"PAP-5130: key is not in the buffer");
 #ifdef CONFIG_REISERFS_CHECK
 	if ( cur_tb ) {
@@ -917,7 +921,7 @@
     }
 	
     // new file gets truncated
-    if (inode_items_version (inode) == ITEM_VERSION_2) {
+    if (get_inode_item_key_version (inode) == KEY_FORMAT_3_6) {
 	// 
 	round_len = ROUND_UP (new_file_length); 
 	/* this was n_new_file_length < le_ih ... */
@@ -992,10 +996,6 @@
     struct item_head    * p_le_ih = PATH_PITEM_HEAD(p_s_path);
     struct buffer_head  * p_s_bh = PATH_PLAST_BUFFER(p_s_path);
 
-#ifdef CONFIG_REISERFS_CHECK
-    int n_repeat_counter = 0;
-#endif
-
     /* Stat_data item. */
     if ( is_statdata_le_ih (p_le_ih) ) {
 
@@ -1020,13 +1020,11 @@
     {
 	int                   n_unfm_number,    /* Number of the item unformatted nodes. */
 	    n_counter,
-	    n_retry,        /* Set to one if there is unformatted node buffer in use. */
 	    n_blk_size;
 	__u32               * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
 	__u32 tmp;
 	struct item_head      s_ih;           /* Item header. */
 	char                  c_mode;           /* Returned mode of the balance. */
-	struct buffer_head  * p_s_un_bh;
 	int need_research;
 
 
@@ -1099,8 +1097,8 @@
 	    // note: path could be changed, first line in for loop takes care
 	    // of it
 
-	    for ( n_retry = 0, n_counter = *p_n_removed;
-		  n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- )  {
+	    for (n_counter = *p_n_removed;
+		 n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- ) {
 
 		if (item_moved (&s_ih, p_s_path)) {
 		    need_research = 1 ;
@@ -1110,69 +1108,23 @@
 			p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
 			"vs-5265: pointer out of range");
 
-		if ( ! get_block_num(p_n_unfm_pointer,0) )  { /* Hole, nothing to remove. */
-		    if ( ! n_retry )
+		/* Hole, nothing to remove. */
+		if ( ! get_block_num(p_n_unfm_pointer,0) )  { 
 			(*p_n_removed)++;
-		    continue;
-		}
-		/* Search for the buffer in cache. */
-		p_s_un_bh = get_hash_table(p_s_sb->s_dev, get_block_num(p_n_unfm_pointer,0), n_blk_size);
-
-		if (p_s_un_bh) {
-		    mark_buffer_clean(p_s_un_bh) ;
-		    if (buffer_locked(p_s_un_bh)) {
-		  __wait_on_buffer(p_s_un_bh) ;
-		    }
-		    /* even if the item moves, the block number of the
-		    ** unformatted node we want to cut won't.  So, it was
-		    ** safe to clean the buffer here, this block _will_
-		    ** get freed during this call to prepare_for_delete_or_cut
-		    */
-		  if ( item_moved (&s_ih, p_s_path) )  {
-		      need_research = 1;
-		      brelse(p_s_un_bh) ;
-		      break ;
-		  }
+			continue;
 		}
-		if ( p_s_un_bh && block_in_use (p_s_un_bh)) {
-		    /* Block is locked or held more than by one holder and by
-                       journal. */
 
-#ifdef CONFIG_REISERFS_CHECK
-		    if (n_repeat_counter && (n_repeat_counter % 100000) == 0) {
-		      printk("prepare_for_delete, waiting on buffer %lu, b_count %d, %s%cJDIRTY %cJDIRTY_WAIT\n", 
-			     p_s_un_bh->b_blocknr, atomic_read (&p_s_un_bh->b_count),
-			     buffer_locked (p_s_un_bh) ? "locked, " : "",
-			     buffer_journaled(p_s_un_bh) ? ' ' : '!', 
-			     buffer_journal_dirty(p_s_un_bh) ? ' ' : '!') ;
-
-		    }
-#endif
-		    n_retry = 1;
-		    brelse (p_s_un_bh);
-		    continue;
-		}
-      
-		if ( ! n_retry )
-		    (*p_n_removed)++;
-      
-		RFALSE( p_s_un_bh &&
-                     get_block_num(p_n_unfm_pointer, 0) != p_s_un_bh->b_blocknr,
-		    // note: minix_truncate allows that. As truncate is
-		    // protected by down (inode->i_sem), two truncates can not
-		    // co-exist
-		    "PAP-5280: blocks numbers are different");	
+		(*p_n_removed)++;
 
 		tmp = get_block_num(p_n_unfm_pointer,0);
 		put_block_num(p_n_unfm_pointer, 0, 0);
 		journal_mark_dirty (th, p_s_sb, p_s_bh);
-		bforget (p_s_un_bh);
 		inode->i_blocks -= p_s_sb->s_blocksize / 512;
 		reiserfs_free_block(th, tmp);
 		if ( item_moved (&s_ih, p_s_path) )  {
-		    need_research = 1;
-		    break ;
-		    }
+			need_research = 1;
+			break ;
+		}
 	    }
 
 	    /* a trick.  If the buffer has been logged, this
@@ -1182,28 +1134,6 @@
 	    */
 	    reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
 
-	    if ( n_retry ) {
-		/* There is block in use. Wait, they should release it soon */
-
-		RFALSE( *p_n_removed >= n_unfm_number, "PAP-5290: illegal case");
-#ifdef CONFIG_REISERFS_CHECK
-		if ( !(++n_repeat_counter % 500000) ) {
-		    reiserfs_warning("PAP-5300: prepare_for_delete_or_cut: (pid %u): "
-				     "could not delete item %k in (%d) iterations. New file length %Lu. (inode %Ld), Still trying\n",
-				     current->pid, p_s_item_key, n_repeat_counter, n_new_file_length, inode->i_size);
-		    if (n_repeat_counter == 5000000) {
-			print_block (PATH_PLAST_BUFFER(p_s_path), 3, 
-				     PATH_LAST_POSITION (p_s_path) - 2, PATH_LAST_POSITION (p_s_path) + 2);
-			reiserfs_panic(p_s_sb, "PAP-5305: prepare_for_delete_or_cut: key %k, new_file_length %Ld",
-				       p_s_item_key, n_new_file_length);
-		    }
-		}
-#endif
-
-		run_task_queue(&tq_disk);
-		current->policy |= SCHED_YIELD;
-		schedule();
-	    }
 	    /* This loop can be optimized. */
 	} while ( (*p_n_removed < n_unfm_number || need_research) &&
 		  search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND );
@@ -1388,8 +1318,8 @@
 
 
 /* this deletes item which never gets split */
-static void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
-					struct key * key)
+void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
+				 struct key * key)
 {
     struct tree_balance tb;
     INITIALIZE_PATH (path);
@@ -1403,13 +1333,13 @@
     while (1) {
 	retval = search_item (th->t_super, &cpu_key, &path);
 	if (retval == IO_ERROR) {
-	    reiserfs_warning ("vs-: reiserfs_delete_solid_item: "
+	    reiserfs_warning ("vs-5350: reiserfs_delete_solid_item: "
 			      "i/o failure occurred trying to delete %K\n", &cpu_key);
 	    break;
 	}
 	if (retval != ITEM_FOUND) {
 	    pathrelse (&path);
-	    reiserfs_warning ("vs-: reiserfs_delete_solid_item: %k not found",
+	    reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found",
 			      key);
 	    break;
 	}
@@ -1429,7 +1359,7 @@
 	}
 
 	// IO_ERROR, NO_DISK_SPACE, etc
-	reiserfs_warning ("vs-: reiserfs_delete_solid_item: "
+	reiserfs_warning ("vs-5360: reiserfs_delete_solid_item: "
 			  "could not delete %K due to fix_nodes failure\n", &cpu_key);
 	unfix_nodes (&tb);
 	break;
@@ -1446,15 +1376,6 @@
     /* for directory this deletes item containing "." and ".." */
     reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
     
-    /* delete stat data */
-    /* this debug code needs to go away.  Trying to find a truncate race
-    ** -- clm -- 4/1/2000
-    */
-#if 0
-    if (inode->i_nlink != 0) {
-        reiserfs_warning("clm-4001: deleting inode with link count==%d\n", inode->i_nlink) ;
-    }
-#endif
 #if defined( USE_INODE_GENERATION_COUNTER )
     if( !old_format_only ( th -> t_super ) )
       {
@@ -1491,7 +1412,7 @@
     */
     if (atomic_read(&p_s_inode->i_count) > 1 || 
         !tail_has_to_be_packed (p_s_inode) || 
-	!page || p_s_inode->u.reiserfs_i.nopack) {
+        !page || (p_s_inode->u.reiserfs_i.i_flags & i_nopack_mask)) {
 	// leave tail in an unformatted node	
 	*p_c_mode = M_SKIP_BALANCING;
 	cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));
@@ -1693,7 +1614,7 @@
 	** be flushed before the transaction commits, so we don't need to 
 	** deal with it here.
 	*/
-	p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ;
+	p_s_inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask;
     }
     return n_ret_value;
 }
@@ -1702,14 +1623,14 @@
 static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode)
 {
     if (inode->i_nlink)
-	reiserfs_warning ("vs-5655: truncate_directory: link count != 0");
+	reiserfs_warning ("vs-5655: truncate_directory: link count != 0\n");
 
-    set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), DOT_OFFSET);
-    set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_DIRENTRY);
+    set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET);
+    set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY);
     reiserfs_delete_solid_item (th, INODE_PKEY (inode));
 
-    set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), SD_OFFSET);
-    set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_STAT_DATA);    
+    set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET);
+    set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA);    
 }
 
 
@@ -1782,6 +1703,7 @@
 	pathrelse(&s_search_path);
 	return;
     }
+
     /* Update key to search for the last file item. */
     set_cpu_key_k_offset (&s_item_key, n_file_size);
 
@@ -1818,7 +1740,6 @@
 
 	  if (update_timestamps) {
 	      p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME;
-	      // FIXME: sd gets wrong size here
 	  } 
 	  reiserfs_update_sd(th, p_s_inode) ;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- linux-2.4.16/fs/reiserfs/super.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/super.c	Thu Dec  6 16:21:36 2001
@@ -26,6 +26,9 @@
 char reiserfs_super_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
 char reiser2fs_super_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
 
+static int reiserfs_remount (struct super_block * s, int * flags, char * data);
+static int reiserfs_statfs (struct super_block * s, struct statfs * buf);
+
 //
 // a portion of this function, particularly the VFS interface portion,
 // was derived from minix or ext2's analog and evolved as the
@@ -33,7 +36,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-void reiserfs_write_super (struct super_block * s)
+static void reiserfs_write_super (struct super_block * s)
 {
 
   int dirty = 0 ;
@@ -52,7 +55,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-void reiserfs_write_super_lockfs (struct super_block * s)
+static void reiserfs_write_super_lockfs (struct super_block * s)
 {
 
   int dirty = 0 ;
@@ -73,6 +76,247 @@
   reiserfs_allow_writes(s) ;
 }
 
+extern const struct key  MAX_KEY;
+
+
+/* this is used to delete "save link" when there are no items of a
+   file it points to. It can either happen if unlink is completed but
+   "save unlink" removal, or if file has both unlink and truncate
+   pending and as unlink completes first (because key of "save link"
+   protecting unlink is bigger that a key lf "save link" which
+   protects truncate), so there left no items to make truncate
+   completion on */
+static void remove_save_link_only (struct super_block * s, struct key * key)
+{
+    struct reiserfs_transaction_handle th;
+
+     /* we are going to do one balancing */
+     journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
+ 
+     reiserfs_delete_solid_item (&th, key);
+     if (is_direct_le_key (KEY_FORMAT_3_5, key))
+        /* removals are protected by direct items */
+        reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
+
+     journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
+}
+ 
+ 
+/* look for uncompleted unlinks and truncates and complete them */
+static void finish_unfinished (struct super_block * s)
+{
+    INITIALIZE_PATH (path);
+    struct cpu_key max_cpu_key, obj_key;
+    struct key save_link_key;
+    int retval;
+    struct item_head * ih;
+    struct buffer_head * bh;
+    int item_pos;
+    char * item;
+    int done;
+    struct inode * inode;
+    int truncate;
+ 
+ 
+    /* compose key to look for "save" links */
+    max_cpu_key.version = KEY_FORMAT_3_5;
+    max_cpu_key.on_disk_key = MAX_KEY;
+    max_cpu_key.key_length = 3;
+ 
+    done = 0;
+    s -> u.reiserfs_sb.s_is_unlinked_ok = 1;
+    while (1) {
+        retval = search_item (s, &max_cpu_key, &path);
+        if (retval != ITEM_NOT_FOUND) {
+            reiserfs_warning ("vs-2140: finish_unfinished: search_by_key returned %d\n",
+                              retval);
+            break;
+        }
+        
+        bh = get_last_bh (&path);
+        item_pos = get_item_pos (&path);
+        if (item_pos != B_NR_ITEMS (bh)) {
+            reiserfs_warning ("vs-2060: finish_unfinished: wrong position found\n");
+            break;
+        }
+        item_pos --;
+        ih = B_N_PITEM_HEAD (bh, item_pos);
+ 
+        if (le32_to_cpu (ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
+            /* there are no "save" links anymore */
+            break;
+ 
+        save_link_key = ih->ih_key;
+        if (is_indirect_le_ih (ih))
+            truncate = 1;
+        else
+            truncate = 0;
+ 
+        /* reiserfs_iget needs k_dirid and k_objectid only */
+        item = B_I_PITEM (bh, ih);
+        obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item);
+        obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid);
+	obj_key.on_disk_key.u.k_offset_v1.k_offset = 0;
+	obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0;
+	
+        pathrelse (&path);
+ 
+        inode = reiserfs_iget (s, &obj_key);
+        if (!inode) {
+            /* the unlink almost completed, it just did not manage to remove
+	       "save" link and release objectid */
+            reiserfs_warning ("vs-2180: finish_unfinished: iget failed for %K\n",
+                              &obj_key);
+            remove_save_link_only (s, &save_link_key);
+            continue;
+        }
+
+	if (!truncate && inode->i_nlink) {
+	    /* file is not unlinked */
+            reiserfs_warning ("vs-2185: finish_unfinished: file %K is not unlinked\n",
+                              &obj_key);
+            remove_save_link_only (s, &save_link_key);
+            continue;
+	}
+ 
+        if (truncate) {
+            inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask;
+            /* not completed truncate found. New size was committed together
+	       with "save" link */
+            reiserfs_warning ("Truncating %k to %Ld ..",
+                              INODE_PKEY (inode), inode->i_size);
+            reiserfs_truncate_file (inode, 0/*don't update modification time*/);
+            remove_save_link (inode, truncate);
+        } else {
+            inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask;
+            /* not completed unlink (rmdir) found */
+            reiserfs_warning ("Removing %k..", INODE_PKEY (inode));
+            /* removal gets completed in iput */
+        }
+ 
+        iput (inode);
+        reiserfs_warning ("done\n");
+        done ++;
+    }
+    s -> u.reiserfs_sb.s_is_unlinked_ok = 0;
+     
+    pathrelse (&path);
+    if (done)
+        reiserfs_warning ("There were %d uncompleted unlinks/truncates. "
+                          "Completed\n", done);
+}
+ 
+/* to protect file being unlinked from getting lost we "safe" link files
+   being unlinked. This link will be deleted in the same transaction with last
+   item of file. mounting the filesytem we scan all these links and remove
+   files which almost got lost */
+void add_save_link (struct reiserfs_transaction_handle * th,
+		    struct inode * inode, int truncate)
+{
+    INITIALIZE_PATH (path);
+    int retval;
+    struct cpu_key key;
+    struct item_head ih;
+    __u32 link;
+
+    /* file can only get one "save link" of each kind */
+    RFALSE( truncate && 
+	    ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ),
+	    "saved link already exists for truncated inode %lx",
+	    ( long ) inode -> i_ino );
+    RFALSE( !truncate && 
+	    ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ),
+	    "saved link already exists for unlinked inode %lx",
+	    ( long ) inode -> i_ino );
+
+    /* setup key of "save" link */
+    key.version = KEY_FORMAT_3_5;
+    key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID;
+    key.on_disk_key.k_objectid = inode->i_ino;
+    if (!truncate) {
+	/* unlink, rmdir, rename */
+	set_cpu_key_k_offset (&key, 1 + inode->i_sb->s_blocksize);
+	set_cpu_key_k_type (&key, TYPE_DIRECT);
+
+	/* item head of "safe" link */
+	make_le_item_head (&ih, &key, key.version, 1 + inode->i_sb->s_blocksize, TYPE_DIRECT,
+			   4/*length*/, 0xffff/*free space*/);
+    } else {
+	/* truncate */
+	set_cpu_key_k_offset (&key, 1);
+	set_cpu_key_k_type (&key, TYPE_INDIRECT);
+
+	/* item head of "safe" link */
+	make_le_item_head (&ih, &key, key.version, 1, TYPE_INDIRECT,
+			   4/*length*/, 0/*free space*/);
+    }
+    key.key_length = 3;
+
+    /* look for its place in the tree */
+    retval = search_item (inode->i_sb, &key, &path);
+    if (retval != ITEM_NOT_FOUND) {
+	reiserfs_warning ("vs-2100: add_save_link:"
+			  "search_by_key (%K) returned %d\n", &key, retval);
+	pathrelse (&path);
+	return;
+    }
+
+    /* body of "save" link */
+    link = cpu_to_le32 (INODE_PKEY (inode)->k_dir_id);
+
+    /* put "save" link inot tree */
+    retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link);
+    if (retval)
+	reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n",
+			  retval);
+    else {
+	if( truncate )
+	    inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask;
+	else
+	    inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask;
+    }
+}
+
+
+/* this opens transaction unlike add_save_link */
+void remove_save_link (struct inode * inode, int truncate)
+{
+    struct reiserfs_transaction_handle th;
+    struct key key;
+ 
+ 
+    /* we are going to do one balancing only */
+    journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+ 
+    /* setup key of "save" link */
+    key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID);
+    key.k_objectid = INODE_PKEY (inode)->k_objectid;
+    if (!truncate) {
+        /* unlink, rmdir, rename */
+        set_le_key_k_offset (KEY_FORMAT_3_5, &key,
+			     1 + inode->i_sb->s_blocksize);
+        set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_DIRECT);
+    } else {
+        /* truncate */
+        set_le_key_k_offset (KEY_FORMAT_3_5, &key, 1);
+        set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_INDIRECT);
+    }
+ 
+    if( ( truncate && 
+          ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ) ) ||
+        ( !truncate && 
+          ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ) ) )
+	reiserfs_delete_solid_item (&th, &key);
+    if (!truncate) {
+	reiserfs_release_objectid (&th, inode->i_ino);
+	inode -> u.reiserfs_i.i_flags &= ~i_link_saved_unlink_mask;
+    } else
+	inode -> u.reiserfs_i.i_flags &= ~i_link_saved_truncate_mask;
+ 
+    journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+}
+
+
 //
 // a portion of this function, particularly the VFS interface portion,
 // was derived from minix or ext2's analog and evolved as the
@@ -80,7 +324,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-void reiserfs_put_super (struct super_block * s)
+static void reiserfs_put_super (struct super_block * s)
 {
   int i;
   struct reiserfs_transaction_handle th ;
@@ -123,6 +367,26 @@
   return;
 }
 
+/* we don't mark inodes dirty, we just log them */
+static void reiserfs_dirty_inode (struct inode * inode) {
+    struct reiserfs_transaction_handle th ;
+
+    if (inode->i_sb->s_flags & MS_RDONLY) {
+        reiserfs_warning("clm-6006: writing inode %lu on readonly FS\n", 
+	                  inode->i_ino) ;
+        return ;
+    }
+    lock_kernel() ;
+
+    /* this is really only used for atime updates, so they don't have
+    ** to be included in O_SYNC or fsync
+    */
+    journal_begin(&th, inode->i_sb, 1) ;
+    reiserfs_update_sd (&th, inode);
+    journal_end(&th, inode->i_sb, 1) ;
+    unlock_kernel() ;
+}
+
 struct super_operations reiserfs_sops = 
 {
   read_inode: reiserfs_read_inode,
@@ -231,7 +495,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_remount (struct super_block * s, int * flags, char * data)
+static int reiserfs_remount (struct super_block * s, int * flags, char * data)
 {
   struct reiserfs_super_block * rs;
   struct reiserfs_transaction_handle th ;
@@ -284,6 +548,10 @@
   /* this will force a full flush of all journal lists */
   SB_JOURNAL(s)->j_must_wait = 1 ;
   journal_end(&th, s, 10) ;
+
+  if (!( *flags & MS_RDONLY ) )
+    finish_unfinished( s );
+
   return 0;
 }
 
@@ -608,7 +876,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent)
+static struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent)
 {
     int size;
     struct inode *root_inode;
@@ -744,6 +1012,10 @@
 
 	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
 	journal_end(&th, s, 1) ;
+	
+	/* look for files which were to be removed in previous session */
+	finish_unfinished (s);
+
 	s->s_dirt = 0;
     } else {
 	struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
@@ -792,7 +1064,7 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-int reiserfs_statfs (struct super_block * s, struct statfs * buf)
+static int reiserfs_statfs (struct super_block * s, struct statfs * buf)
 {
   struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
   
@@ -835,6 +1107,7 @@
 	reiserfs_proc_info_global_done();
         unregister_filesystem(&reiserfs_fs_type);
 }
+
 
 module_init(init_reiserfs_fs) ;
 module_exit(exit_reiserfs_fs) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- linux-2.4.16/fs/reiserfs/tail_conversion.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/reiserfs/tail_conversion.c	Thu Dec  6 16:21:36 2001
@@ -240,7 +240,7 @@
 
 
     /* Set direct item header to insert. */
-    make_le_item_head (&s_ih, 0, inode_items_version (p_s_inode), pos1 + 1,
+    make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1,
 		       TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/);
 
     /* we want a pointer to the first byte of the tail in the page.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/vfat/vfatfs_syms.c linux/fs/vfat/vfatfs_syms.c
--- linux-2.4.16/fs/vfat/vfatfs_syms.c	Mon Nov 26 10:35:00 2001
+++ linux/fs/vfat/vfatfs_syms.c	Tue Dec  4 19:25:31 2001
@@ -33,3 +33,4 @@
 
 module_init(init_vfat_fs)
 module_exit(exit_vfat_fs)
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-i386/cpufeature.h linux/include/asm-i386/cpufeature.h
--- linux-2.4.16/include/asm-i386/cpufeature.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-i386/cpufeature.h	Thu Dec  6 16:30:26 2001
@@ -40,6 +40,7 @@
 #define X86_FEATURE_XMM		(0*32+25) /* Streaming SIMD Extensions */
 #define X86_FEATURE_XMM2	(0*32+26) /* Streaming SIMD Extensions-2 */
 #define X86_FEATURE_SELFSNOOP	(0*32+27) /* CPU self snoop */
+#define X86_FEATURE_HT		(0*32+28) /* Hyper-Threading */
 #define X86_FEATURE_ACC		(0*32+29) /* Automatic clock control */
 #define X86_FEATURE_IA64	(0*32+30) /* IA-64 processor */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-i386/msr.h linux/include/asm-i386/msr.h
--- linux-2.4.16/include/asm-i386/msr.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-i386/msr.h	Wed Dec  5 20:42:55 2001
@@ -81,6 +81,7 @@
 
 #define MSR_K7_EVNTSEL0			0xC0010000
 #define MSR_K7_PERFCTR0			0xC0010004
+#define MSR_K7_HWCR			0xC0010015
 
 /* Centaur-Hauls/IDT defined MSRs. */
 #define MSR_IDT_FCR1			0x107
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- linux-2.4.16/include/asm-i386/pgalloc.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-i386/pgalloc.h	Tue Dec  4 19:25:31 2001
@@ -18,15 +18,21 @@
  * Allocate and free page tables.
  */
 
-#if CONFIG_X86_PAE
+#if defined (CONFIG_X86_PAE)
+/*
+ * We can't include <linux/slab.h> here, thus these uglinesses.
+ */
+struct kmem_cache_s;
+
+extern struct kmem_cache_s *pae_pgd_cachep;
+extern void *kmem_cache_alloc(struct kmem_cache_s *, int);
+extern void kmem_cache_free(struct kmem_cache_s *, void *);
 
-extern void *kmalloc(size_t, int);
-extern void kfree(const void *);
 
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
 	int i;
-	pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+	pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
 
 	if (pgd) {
 		for (i = 0; i < USER_PTRS_PER_PGD; i++) {
@@ -36,32 +42,36 @@
 			clear_page(pmd);
 			set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
 		}
-		memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+		memcpy(pgd + USER_PTRS_PER_PGD,
+			swapper_pg_dir + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
 	return pgd;
 out_oom:
 	for (i--; i >= 0; i--)
 		free_page((unsigned long)__va(pgd_val(pgd[i])-1));
-	kfree(pgd);
+	kmem_cache_free(pae_pgd_cachep, pgd);
 	return NULL;
 }
 
 #else
 
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
 	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
 
 	if (pgd) {
 		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-		memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+		memcpy(pgd + USER_PTRS_PER_PGD,
+			swapper_pg_dir + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
 	return pgd;
 }
 
-#endif
+#endif /* CONFIG_X86_PAE */
 
-static __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
 {
 	unsigned long *ret;
 
@@ -74,21 +84,21 @@
 	return (pgd_t *)ret;
 }
 
-static __inline__ void free_pgd_fast(pgd_t *pgd)
+static inline void free_pgd_fast(pgd_t *pgd)
 {
 	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
 	pgtable_cache_size++;
 }
 
-static __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
 {
-#if CONFIG_X86_PAE
+#if defined(CONFIG_X86_PAE)
 	int i;
 
 	for (i = 0; i < USER_PTRS_PER_PGD; i++)
 		free_page((unsigned long)__va(pgd_val(pgd[i])-1));
-	kfree(pgd);
+	kmem_cache_free(pae_pgd_cachep, pgd);
 #else
 	free_page((unsigned long)pgd);
 #endif
@@ -104,7 +114,8 @@
 	return pte;
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
+					unsigned long address)
 {
 	unsigned long *ret;
 
@@ -116,7 +127,7 @@
 	return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
 {
 	*(unsigned long *)pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
@@ -128,14 +139,9 @@
 	free_page((unsigned long)pte);
 }
 
-#define pte_free(pte)		pte_free_fast(pte)
-#ifdef CONFIG_X86_PAE
-#define pgd_alloc(mm)		get_pgd_slow()
+#define pte_free(pte)		pte_free_slow(pte)
 #define pgd_free(pgd)		free_pgd_slow(pgd)
-#else
 #define pgd_alloc(mm)		get_pgd_fast()
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#endif
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- linux-2.4.16/include/asm-i386/smp.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-i386/smp.h	Thu Dec  6 16:32:26 2001
@@ -57,6 +57,9 @@
 extern unsigned long cpu_online_map;
 extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
+extern int smp_num_siblings;
+extern int cpu_sibling_map[];
+
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h
--- linux-2.4.16/include/asm-ia64/pal.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-ia64/pal.h	Tue Dec  4 19:25:31 2001
@@ -88,10 +88,10 @@
 typedef s64				pal_status_t;
 
 #define PAL_STATUS_SUCCESS		0	/* No error */
-#define PAL_STATUS_UNIMPLEMENTED	-1	/* Unimplemented procedure */
-#define PAL_STATUS_EINVAL		-2	/* Invalid argument */
-#define PAL_STATUS_ERROR		-3	/* Error */
-#define PAL_STATUS_CACHE_INIT_FAIL	-4	/* Could not initialize the
+#define PAL_STATUS_UNIMPLEMENTED	(-1)	/* Unimplemented procedure */
+#define PAL_STATUS_EINVAL		(-2)	/* Invalid argument */
+#define PAL_STATUS_ERROR		(-3)	/* Error */
+#define PAL_STATUS_CACHE_INIT_FAIL	(-4)	/* Could not initialize the
 						 * specified level and type of
 						 * cache without sideeffects
 						 * and "restrict" was 1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-ia64/siginfo.h linux/include/asm-ia64/siginfo.h
--- linux-2.4.16/include/asm-ia64/siginfo.h	Mon Nov 26 10:35:01 2001
+++ linux/include/asm-ia64/siginfo.h	Tue Dec  4 19:25:31 2001
@@ -119,11 +119,11 @@
 
 #define SI_USER		0		/* sent by kill, sigsend, raise */
 #define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
+#define SI_QUEUE	(-1)		/* sent by sigqueue */
 #define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_MESGQ	(-3)		/* sent by real time mesq state change */
+#define SI_ASYNCIO	(-4)		/* sent by AIO completion */
+#define SI_SIGIO	(-5)		/* sent by queued SIGIO */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-ia64/system.h linux/include/asm-ia64/system.h
--- linux-2.4.16/include/asm-ia64/system.h	Mon Nov 26 10:35:01 2001
+++ linux/include/asm-ia64/system.h	Mon Dec 10 17:05:23 2001
@@ -405,6 +405,10 @@
 	ia64_psr(ia64_task_regs(prev))->dfh = 1;				\
 	__switch_to(prev,next,last);						\
   } while (0)
+
+/* Return true if this CPU can call the console drivers in printk() */
+#define arch_consoles_callable() (cpu_online_map & (1UL << smp_processor_id()))
+
 #else
 # define switch_to(prev,next,last) do {						\
 	ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next));	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- linux-2.4.16/include/asm-sparc/bitops.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc/bitops.h	Tue Dec  4 19:25:31 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.65 2001/10/30 04:08:26 davem Exp $
+/* $Id: bitops.h,v 1.67 2001/11/19 18:36:34 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- linux-2.4.16/include/asm-sparc64/bitops.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/bitops.h	Tue Dec  4 19:25:31 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.36 2001/06/14 12:34:49 davem Exp $
+/* $Id: bitops.h,v 1.38 2001/11/19 18:36:34 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,9 +13,9 @@
 extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
 extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
 
-#define test_and_set_bit(nr,addr)	(___test_and_set_bit(nr,addr)!=0)
-#define test_and_clear_bit(nr,addr)	(___test_and_clear_bit(nr,addr)!=0)
-#define test_and_change_bit(nr,addr)	(___test_and_change_bit(nr,addr)!=0)
+#define test_and_set_bit(nr,addr)	({___test_and_set_bit(nr,addr)!=0;})
+#define test_and_clear_bit(nr,addr)	({___test_and_clear_bit(nr,addr)!=0;})
+#define test_and_change_bit(nr,addr)	({___test_and_change_bit(nr,addr)!=0;})
 #define set_bit(nr,addr)		((void)___test_and_set_bit(nr,addr))
 #define clear_bit(nr,addr)		((void)___test_and_clear_bit(nr,addr))
 #define change_bit(nr,addr)		((void)___test_and_change_bit(nr,addr))
@@ -214,8 +214,8 @@
 extern long ___test_and_set_le_bit(int nr, volatile void *addr);
 extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
 
-#define test_and_set_le_bit(nr,addr)	(___test_and_set_le_bit(nr,addr)!=0)
-#define test_and_clear_le_bit(nr,addr)	(___test_and_clear_le_bit(nr,addr)!=0)
+#define test_and_set_le_bit(nr,addr)	({___test_and_set_le_bit(nr,addr)!=0;})
+#define test_and_clear_le_bit(nr,addr)	({___test_and_clear_le_bit(nr,addr)!=0;})
 #define set_le_bit(nr,addr)		((void)___test_and_set_le_bit(nr,addr))
 #define clear_le_bit(nr,addr)		((void)___test_and_clear_le_bit(nr,addr))
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- linux-2.4.16/include/asm-sparc64/page.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/page.h	Fri Dec  7 18:48:52 2001
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.36 2000/08/10 01:04:53 davem Exp $ */
+/* $Id: page.h,v 1.38 2001/11/30 01:04:10 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -18,13 +18,20 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void do_BUG(const char *file, int line);
+#define BUG() do {					\
+	do_BUG(__FILE__, __LINE__);			\
+	__builtin_trap();				\
+} while (0)
+#else
 #define BUG()		__builtin_trap()
+#endif
+
 #define PAGE_BUG(page)	BUG()
 
 extern void _clear_page(void *page);
-extern void _copy_page(void *to, void *from);
 #define clear_page(X)	_clear_page((void *)(X))
-#define copy_page(X,Y)	_copy_page((void *)(X), (void *)(Y))
 extern void clear_user_page(void *page, unsigned long vaddr);
 extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- linux-2.4.16/include/asm-sparc64/pgtable.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/pgtable.h	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.152 2001/11/12 09:43:39 davem Exp $
+/* $Id: pgtable.h,v 1.154 2001/12/05 06:05:36 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,23 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 
+/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 16MB).
+ * The page copy blockops use 0x1000000 to 0x18000000 (16MB --> 24MB).
+ * The PROM resides in an area spanning 0xf0000000 to 0x100000000.
+ * The vmalloc area spans 0x140000000 to 0x200000000.
+ * There is a single static kernel PMD which maps from 0x0 to address
+ * 0x400000000.
+ */
+#define	TLBTEMP_BASE		0x0000000001000000
+#define MODULES_VADDR		0x0000000002000000
+#define MODULES_LEN		0x000000007e000000
+#define MODULES_END		0x0000000080000000
+#define VMALLOC_START		0x0000000140000000
+#define VMALLOC_VMADDR(x)	((unsigned long)(x))
+#define VMALLOC_END		0x0000000200000000
+#define LOW_OBP_ADDRESS		0x00000000f0000000
+#define HI_OBP_ADDRESS		0x0000000100000000
+
 /* XXX All of this needs to be rethought so we can take advantage
  * XXX cheetah's full 64-bit virtual address space, ie. no more hole
  * XXX in the middle like on spitfire. -DaveM
@@ -77,13 +94,6 @@
 				 (1) : (PTRS_PER_PGD)))
 #define FIRST_USER_PGD_NR	0
 
-/* NOTE: TLB miss handlers depend heavily upon where this is. */
-#define VMALLOC_START		0x0000000140000000UL
-#define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#define VMALLOC_END		0x0000000200000000UL
-#define LOW_OBP_ADDRESS		0xf0000000UL
-#define HI_OBP_ADDRESS		0x100000000UL
-
 #define pte_ERROR(e)	__builtin_trap()
 #define pmd_ERROR(e)	__builtin_trap()
 #define pgd_ERROR(e)	__builtin_trap()
@@ -290,8 +300,6 @@
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
 
 extern unsigned long prom_virt_to_phys(unsigned long, int *);
-#define LOW_OBP_ADDRESS		0xf0000000UL
-#define HI_OBP_ADDRESS		0x100000000UL
 
 extern __inline__ unsigned long
 sun4u_get_pte (unsigned long addr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- linux-2.4.16/include/asm-sparc64/processor.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/processor.h	Tue Dec  4 19:25:31 2001
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.76 2001/10/08 09:32:13 davem Exp $
+/* $Id: processor.h,v 1.80 2001/11/17 00:10:48 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -66,6 +66,15 @@
 	unsigned long gsr[7];
 	unsigned long xfsr[7];
 
+#ifdef CONFIG_DEBUG_SPINLOCK
+	/* How many spinlocks held by this thread.
+	 * Used with spin lock debugging to catch tasks
+	 * sleeping illegally with locks held.
+	 */
+	int smp_lock_count;
+	unsigned int smp_lock_pc;
+#endif
+
 	struct reg_window reg_window[NSWINS];
 	unsigned long rwbuf_stkptrs[NSWINS];
 	
@@ -88,6 +97,7 @@
 #define FAULT_CODE_ITLB		0x04	/* Miss happened in I-TLB		*/
 #define FAULT_CODE_WINFIXUP	0x08	/* Miss happened during spill/fill	*/
 
+#ifndef CONFIG_DEBUG_SPINLOCK
 #define INIT_THREAD  {					\
 /* ksp, wstate, cwp, flags, current_ds, */ 		\
    0,   0,      0,   0,     KERNEL_DS,			\
@@ -104,6 +114,24 @@
 /* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
    0,          0,          0,		 0,            0, \
 }
+#else /* CONFIG_DEBUG_SPINLOCK */
+#define INIT_THREAD  {					\
+/* ksp, wstate, cwp, flags, current_ds, */ 		\
+   0,   0,      0,   0,     KERNEL_DS,			\
+/* w_saved, fpdepth, fault_code, use_blkcommit, */	\
+   0,       0,       0,          0,			\
+/* fault_address, fpsaved, __pad2, kregs, */		\
+   0,             { 0 },   0,      0,			\
+/* utraps, gsr,   xfsr,  smp_lock_count, smp_lock_pc, */\
+   0,	   { 0 }, { 0 }, 0,		 0,		\
+/* reg_window */					\
+   { { { 0, }, { 0, } }, }, 				\
+/* rwbuf_stkptrs */					\
+   { 0, 0, 0, 0, 0, 0, 0, },				\
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+   0,          0,          0,		 0,            0, \
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
 
 #ifdef __KERNEL__
 #if PAGE_SHIFT == 13
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/rwsem.h linux/include/asm-sparc64/rwsem.h
--- linux-2.4.16/include/asm-sparc64/rwsem.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/rwsem.h	Tue Dec  4 19:25:31 2001
@@ -1,4 +1,4 @@
-/* $Id: rwsem.h,v 1.4 2001/04/26 02:36:36 davem Exp $
+/* $Id: rwsem.h,v 1.5 2001/11/18 00:12:56 davem Exp $
  * rwsem.h: R/W semaphores implemented using CAS
  *
  * Written by David S. Miller (davem@redhat.com), 2001.
@@ -59,7 +59,7 @@
 		" add		%%g7, 1, %%g7\n\t"
 		"cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -92,7 +92,7 @@
 		"bne,pn		%%icc, 1b\n\t"
 		" cmp		%%g7, 0\n\t"
 		"bne,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -122,7 +122,7 @@
 		"bne,pn		%%icc, 1b\n\t"
 		" cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tsethi	%%hi(%2), %%g1\n\t"
@@ -160,7 +160,7 @@
 		" sub		%%g7, %%g1, %%g7\n\t"
 		"cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection 2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -189,7 +189,7 @@
 		"cas		[%2], %%g5, %%g7\n\t"
 		"cmp		%%g5, %%g7\n\t"
 		"bne,pn		%%icc, 1b\n\t"
-		" nop\n\t"
+		" membar	#StoreLoad | #StoreStore\n\t"
 		"mov		%%g7, %0\n\t"
 		: "=&r" (tmp)
 		: "0" (tmp), "r" (sem)
@@ -208,7 +208,7 @@
 
 again:
 	__asm__ __volatile__("cas	[%2], %3, %0\n\t"
-			     "membar	#StoreStore | #StoreLoad"
+			     "membar	#StoreLoad | #StoreStore"
 			     : "=&r" (prev)
 			     : "0" (new), "r" (sem), "r" (old)
 			     : "memory");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- linux-2.4.16/include/asm-sparc64/semaphore.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/semaphore.h	Tue Dec  4 19:25:31 2001
@@ -75,7 +75,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreStore\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g5\n"
@@ -120,7 +120,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreStore\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%2, %%g5\n"
@@ -173,7 +173,7 @@
 "	cmp	%%g5, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 mov	0, %0\n"
-"	membar	#StoreStore\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 	: "=&r" (ret)
 	: "r" (sem)
@@ -207,7 +207,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 addcc	%%g7, 1, %%g0\n"
 "	ble,pn	%%icc, 3f\n"
-"	 nop\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g5\n"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- linux-2.4.16/include/asm-sparc64/smp.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/smp.h	Tue Dec  4 19:25:31 2001
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <linux/cache.h>
 #include <asm/asi.h>
 #include <asm/starfire.h>
 #include <asm/spitfire.h>
@@ -34,7 +35,7 @@
 /* Per processor Sparc parameters we need. */
 
 /* Keep this a multiple of 64-bytes for cache reasons. */
-struct cpuinfo_sparc {
+typedef struct {
 	/* Dcache line 1 */
 	unsigned int	__pad0;		/* bh_count moved to irq_stat for consistency. KAO */
 	unsigned int	multiplier;
@@ -51,9 +52,9 @@
 
 	/* Dcache lines 3 and 4 */
 	unsigned int	irq_worklists[16];
-};
+} ____cacheline_aligned cpuinfo_sparc;
 
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern cpuinfo_sparc cpu_data[NR_CPUS];
 
 /*
  *	Private routines/data
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/smplock.h linux/include/asm-sparc64/smplock.h
--- linux-2.4.16/include/asm-sparc64/smplock.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/smplock.h	Thu Dec  6 15:33:53 2001
@@ -9,7 +9,9 @@
 
 extern spinlock_t kernel_flag;
 
-#define kernel_locked()		spin_is_locked(&kernel_flag)
+#define kernel_locked()			\
+	(spin_is_locked(&kernel_flag) &&\
+	 (current->lock_depth >= 0))
 
 /*
  * Release global kernel lock and global interrupt lock
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- linux-2.4.16/include/asm-sparc64/spinlock.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/spinlock.h	Tue Dec  4 19:25:31 2001
@@ -6,11 +6,13 @@
 #ifndef __SPARC64_SPINLOCK_H
 #define __SPARC64_SPINLOCK_H
 
+#include <linux/config.h>
+
 #ifndef __ASSEMBLY__
 
 /* To get debugging spinlocks which detect and catch
- * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
- * specific makefile and rebuild your kernel.
+ * deadlock situations, set CONFIG_DEBUG_SPINLOCK
+ * and rebuild your kernel.
  */
 
 /* All of these locking primitives are expected to work properly
@@ -26,7 +28,7 @@
  * must be pre-V9 branches.
  */
 
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED	0
@@ -75,7 +77,7 @@
 			     : "memory");
 }
 
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
 	unsigned char lock;
@@ -101,11 +103,11 @@
 #define spin_lock(lock)		_do_spin_lock(lock, "spin_lock")
 #define spin_unlock(lock)	_do_spin_unlock(lock)
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
 
 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
 
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 
 typedef unsigned int rwlock_t;
 #define RW_LOCK_UNLOCKED	0
@@ -121,7 +123,7 @@
 #define write_lock(p)	__write_lock(p)
 #define write_unlock(p)	__write_unlock(p)
 
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
 	unsigned long lock;
@@ -164,7 +166,7 @@
 	__restore_flags(flags); \
 } while(0)
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
 
 #endif /* !(__ASSEMBLY__) */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h
--- linux-2.4.16/include/asm-sparc64/spitfire.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/spitfire.h	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.16 2001/09/24 21:17:57 kanoj Exp $
+/* $Id: spitfire.h,v 1.18 2001/11/29 16:42:10 kanoj Exp $
  * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -32,6 +32,8 @@
 #define VIRT_WATCHPOINT		0x0000000000000038
 #define PHYS_WATCHPOINT		0x0000000000000040
 
+#define SPITFIRE_HIGHEST_LOCKED_TLBENT	(64 - 1)
+
 #ifndef __ASSEMBLY__
 
 enum ultra_tlb_layout {
@@ -43,7 +45,6 @@
 
 #define SPARC64_USE_STICK	(tlb_type == cheetah)
 
-#define SPITFIRE_HIGHEST_LOCKED_TLBENT	(64 - 1)
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
 #define L1DCACHE_SIZE		0x4000
@@ -357,12 +358,17 @@
  * 2 way assosciative, and holds 512 entries.  The fourth TLB is for
  * instruction accesses to 8K non-locked translations, is 2 way
  * assosciative, and holds 128 entries.
+ *
+ * Cheetah has some bug where bogus data can be returned from
+ * ASI_{D,I}TLB_DATA_ACCESS loads, doing the load twice fixes
+ * the problem for me. -DaveM
  */
 extern __inline__ unsigned long cheetah_get_ldtlb_data(int entry)
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((0 << 16) | (entry << 3)),
 			     "i" (ASI_DTLB_DATA_ACCESS));
@@ -374,7 +380,8 @@
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((0 << 16) | (entry << 3)),
 			     "i" (ASI_ITLB_DATA_ACCESS));
@@ -430,7 +437,8 @@
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
 
@@ -461,7 +469,8 @@
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((2 << 16) | (entry << 3)),
                                "i" (ASI_ITLB_DATA_ACCESS));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- linux-2.4.16/include/asm-sparc64/system.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/system.h	Tue Dec  4 19:25:31 2001
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.64 2001/08/30 03:22:00 kanoj Exp $ */
+/* $Id: system.h,v 1.68 2001/11/18 00:12:56 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -145,6 +145,24 @@
 #define flush_register_windows flushw_all
 #define prepare_to_switch flushw_all
 
+#ifndef CONFIG_DEBUG_SPINLOCk
+#define CHECK_LOCKS(PREV)	do { } while(0)
+#else /* CONFIG_DEBUG_SPINLOCk */
+#define CHECK_LOCKS(PREV)						\
+if ((PREV)->thread.smp_lock_count) {					\
+	unsigned long rpc;						\
+	__asm__ __volatile__("mov %%i7, %0" : "=r" (rpc));		\
+	printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n",	\
+	       (PREV)->comm, (PREV)->pid,				\
+	       (PREV)->thread.smp_lock_count);				\
+	printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n",		\
+	       (PREV)->comm, (PREV)->pid,				\
+	       (PREV)->thread.smp_lock_pc);				\
+	printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n",		\
+	       (PREV)->comm, (PREV)->pid, rpc);				\
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCk) */
+
 	/* See what happens when you design the chip correctly?
 	 *
 	 * We tell gcc we clobber all non-fixed-usage registers except
@@ -155,7 +173,8 @@
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
 #define switch_to(prev, next, last)						\
-do {	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
+do {	CHECK_LOCKS(prev);							\
+	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		unsigned long __tmp;						\
 		read_pcr(__tmp);						\
 		current->thread.pcr_reg = __tmp;				\
@@ -276,7 +295,7 @@
 __cmpxchg_u32(volatile int *m, int old, int new)
 {
 	__asm__ __volatile__("cas [%2], %3, %0\n\t"
-			     "membar #StoreStore | #StoreLoad"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=&r" (new)
 			     : "0" (new), "r" (m), "r" (old)
 			     : "memory");
@@ -288,7 +307,7 @@
 __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
 {
 	__asm__ __volatile__("casx [%2], %3, %0\n\t"
-			     "membar #StoreStore | #StoreLoad"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=&r" (new)
 			     : "0" (new), "r" (m), "r" (old)
 			     : "memory");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- linux-2.4.16/include/asm-sparc64/ttable.h	Mon Nov 26 10:35:00 2001
+++ linux/include/asm-sparc64/ttable.h	Thu Dec  6 15:33:53 2001
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */
+/* $Id: ttable.h,v 1.17 2001/11/28 23:32:16 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -29,6 +29,15 @@
 	 clr	%l6;					\
 	nop;
 
+#define TRAP_7INSNS(routine)				\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etrap;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;
+
 #define TRAP_SAVEFPU(routine)				\
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, do_fptrap;			\
@@ -43,6 +52,11 @@
 	ba,pt	%xcc, routine;				\
 	 nop;						\
 	nop; nop; nop; nop; nop; nop;
+	
+#define TRAP_NOSAVE_7INSNS(routine)			\
+	ba,pt	%xcc, routine;				\
+	 nop;						\
+	nop; nop; nop; nop; nop;
 	
 #define TRAPTL1(routine)				\
 	sethi	%hi(109f), %g7;				\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/cache.h linux/include/linux/cache.h
--- linux-2.4.16/include/linux/cache.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/cache.h	Fri Dec  7 18:58:23 2001
@@ -34,4 +34,12 @@
 #endif
 #endif /* __cacheline_aligned */
 
+#ifndef __cacheline_aligned_in_smp
+#ifdef CONFIG_SMP
+#define __cacheline_aligned_in_smp __cacheline_aligned
+#else
+#define __cacheline_aligned_in_smp
+#endif /* CONFIG_SMP */
+#endif
+
 #endif /* __LINUX_CACHE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/coda_linux.h linux/include/linux/coda_linux.h
--- linux-2.4.16/include/linux/coda_linux.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/coda_linux.h	Wed Dec  5 16:28:13 2001
@@ -92,12 +92,6 @@
     printk(format, ## a); }                                       \
 } while (0)
 
-#define ENTRY    \
-    if(coda_print_entry) printk("Process %d entered %s\n",current->pid,__FUNCTION__)
-
-#define EXIT    \
-    if(coda_print_entry) printk("Process %d leaving %s\n",current->pid,__FUNCTION__)
-
 #define CODA_ALLOC(ptr, cast, size)                                       \
 do {                                                                      \
     if (size < PAGE_SIZE) {                                               \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- linux-2.4.16/include/linux/devfs_fs_kernel.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/devfs_fs_kernel.h	Tue Dec  4 19:25:31 2001
@@ -37,8 +37,7 @@
 				       */
 #define DEVFS_FL_REMOVABLE      0x010 /* This is a removable media device    */
 #define DEVFS_FL_WAIT           0x020 /* Wait for devfsd to finish           */
-#define DEVFS_FL_NO_PERSISTENCE 0x040 /* Forget changes after unregister     */
-#define DEVFS_FL_CURRENT_OWNER  0x080 /* Set initial ownership to current    */
+#define DEVFS_FL_CURRENT_OWNER  0x040 /* Set initial ownership to current    */
 #define DEVFS_FL_DEFAULT        DEVFS_FL_NONE
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/eeprom.h linux/include/linux/eeprom.h
--- linux-2.4.16/include/linux/eeprom.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/eeprom.h	Sun Dec  9 22:57:53 2001
@@ -1,6 +1,7 @@
 /* credit winbond-840.c
  */
 #include <asm/io.h>
+
 struct eeprom_ops {
 	void	(*set_cs)(void *ee);
 	void	(*clear_cs)(void *ee);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/ext3_fs.h linux/include/linux/ext3_fs.h
--- linux-2.4.16/include/linux/ext3_fs.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/ext3_fs.h	Thu Dec  6 20:42:51 2001
@@ -36,8 +36,8 @@
 /*
  * The second extended file system version
  */
-#define EXT3FS_DATE		"06 Nov 2001"
-#define EXT3FS_VERSION		"2.4-0.9.15"
+#define EXT3FS_DATE		"02 Dec 2001"
+#define EXT3FS_VERSION		"2.4-0.9.16"
 
 /*
  * Debug code
@@ -577,10 +577,6 @@
 					 ~EXT3_DIR_ROUND)
 
 #ifdef __KERNEL__
-
-/* Filesize hard limits for 64-bit file offsets */
-extern long long ext3_max_sizes[];
-
 /*
  * Describe an inode's exact location on disk and in memory
  */
@@ -603,9 +599,6 @@
 # define ATTRIB_NORET  __attribute__((noreturn))
 # define NORET_AND     noreturn,
 
-/* acl.c */
-extern int ext3_permission (struct inode *, int);
-
 /* balloc.c */
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
@@ -619,16 +612,10 @@
 						    unsigned int block_group,
 						    struct buffer_head ** bh);
 
-/* bitmap.c */
-extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
-
 /* dir.c */
 extern int ext3_check_dir_entry(const char *, struct inode *,
 				struct ext3_dir_entry_2 *, struct buffer_head *,
 				unsigned long);
-
-/* file.c */
-
 /* fsync.c */
 extern int ext3_sync_file (struct file *, struct dentry *, int);
 
@@ -638,9 +625,9 @@
 extern struct inode * ext3_orphan_get (struct super_block *, ino_t);
 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);
 
 /* inode.c */
-
 extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
 
@@ -654,13 +641,13 @@
 extern void ext3_discard_prealloc (struct inode *);
 extern void ext3_dirty_inode(struct inode *);
 extern int ext3_change_inode_journal_flag(struct inode *, int);
+extern void ext3_truncate (struct inode *);
 
 /* ioctl.c */
 extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
 		       unsigned long);
 
 /* namei.c */
-extern struct inode_operations ext3_dir_inode_operations;
 extern int ext3_orphan_add(handle_t *, struct inode *);
 extern int ext3_orphan_del(handle_t *, struct inode *);
 
@@ -684,9 +671,6 @@
 extern struct super_block * ext3_read_super (struct super_block *,void *,int);
 extern int ext3_statfs (struct super_block *, struct statfs *);
 
-/* truncate.c */
-extern void ext3_truncate (struct inode *);
-
 #define ext3_std_error(sb, errno)				\
 do {								\
 	if ((errno))						\
@@ -705,10 +689,15 @@
 extern struct inode_operations ext3_file_inode_operations;
 extern struct file_operations ext3_file_operations;
 
+/* inode.c */
+extern struct address_space_operations ext3_aops;
+
+/* namei.c */
+extern struct inode_operations ext3_dir_inode_operations;
+
 /* symlink.c */
 extern struct inode_operations ext3_fast_symlink_inode_operations;
 
-extern struct address_space_operations ext3_aops;
 
 #endif	/* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/ext3_jbd.h linux/include/linux/ext3_jbd.h
--- linux-2.4.16/include/linux/ext3_jbd.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/ext3_jbd.h	Thu Dec  6 20:42:51 2001
@@ -196,9 +196,22 @@
  */
 static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks)
 {
+	journal_t *journal;
+	
 	if (inode->i_sb->s_flags & MS_RDONLY)
 		return ERR_PTR(-EROFS);
-	return journal_start(EXT3_JOURNAL(inode), nblocks);
+
+	/* Special case here: if the journal has aborted behind our
+	 * backs (eg. EIO in the commit thread), then we still need to
+	 * take the FS itself readonly cleanly. */
+	journal = EXT3_JOURNAL(inode);
+	if (is_journal_aborted(journal)) {
+		ext3_abort(inode->i_sb, __FUNCTION__,
+			   "Detected aborted journal");
+		return ERR_PTR(-EROFS);
+	}
+	
+	return journal_start(journal, nblocks);
 }
 
 static inline handle_t *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.16/include/linux/fs.h	Mon Nov 26 10:35:11 2001
+++ linux/include/linux/fs.h	Tue Dec  4 19:25:31 2001
@@ -854,6 +854,8 @@
 	int (*getattr) (struct dentry *, struct iattr *);
 };
 
+struct seq_file;
+
 /*
  * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
  * without the big kernel lock held in all filesystems.
@@ -905,6 +907,7 @@
 	 */
 	struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
 	int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent);
+	int (*show_options)(struct seq_file *, struct vfsmount *);
 };
 
 /* Inode state bits.. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/highmem.h linux/include/linux/highmem.h
--- linux-2.4.16/include/linux/highmem.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/highmem.h	Fri Dec  7 18:48:52 2001
@@ -93,15 +93,4 @@
 	kunmap_atomic(vto, KM_USER1);
 }
 
-static inline void copy_highpage(struct page *to, struct page *from)
-{
-	char *vfrom, *vto;
-
-	vfrom = kmap(from);
-	vto = kmap(to);
-	copy_page(vto, vfrom);
-	kunmap(from);
-	kunmap(to);
-}
-
 #endif /* _LINUX_HIGHMEM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/i8k.h linux/include/linux/i8k.h
--- linux-2.4.16/include/linux/i8k.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/i8k.h	Tue Dec  4 19:25:31 2001
@@ -1,5 +1,5 @@
 /*
- * i8k.h -- Linux driver for accessing the SMM BIOS on Dell I8000 laptops
+ * i8k.h -- Linux driver for accessing the SMM BIOS on Dell laptops
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
@@ -36,9 +36,9 @@
 #define I8K_FAN_HIGH		2
 #define I8K_FAN_MAX		I8K_FAN_HIGH
 
-#define I8K_VOL_UP		0x01
-#define I8K_VOL_DOWN		0x02
-#define I8K_VOL_MUTE		0x03
+#define I8K_VOL_UP		1
+#define I8K_VOL_DOWN		2
+#define I8K_VOL_MUTE		4
 
 #define I8K_AC			1
 #define I8K_BATTERY		0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/init.h linux/include/linux/init.h
--- linux-2.4.16/include/linux/init.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/init.h	Fri Dec  7 18:08:44 2001
@@ -111,7 +111,7 @@
  */
 #define module_exit(x)	__exitcall(x);
 
-#else
+#else	/* MODULE */
 
 #define __init
 #define __exit
@@ -141,7 +141,7 @@
 
 #define __setup(str,func) /* nothing */
 
-#endif
+#endif	/* !MODULE */
 
 #ifdef CONFIG_HOTPLUG
 #define __devinit
@@ -153,6 +153,18 @@
 #define __devinitdata __initdata
 #define __devexit __exit
 #define __devexitdata __exitdata
+#endif
+
+/* Functions marked as __devexit may be discarded at kernel link time, depending
+   on config options.  Newer versions of binutils detect references from
+   retained sections to discarded sections and flag an error.  Pointers to
+   __devexit functions must use __devexit_p(function_name), the wrapper will
+   insert either the function_name or NULL, depending on the config options.
+ */
+#if defined(MODULE) || defined(CONFIG_HOTPLUG)
+#define __devexit_p(x) x
+#else
+#define __devexit_p(x) NULL
 #endif
 
 #endif /* _LINUX_INIT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/isdn/tpam.h linux/include/linux/isdn/tpam.h
--- linux-2.4.16/include/linux/isdn/tpam.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/isdn/tpam.h	Sun Dec  9 19:23:11 2001
@@ -1,4 +1,4 @@
-/* $Id: tpam.h,v 1.1.2.1 2001/06/08 08:23:46 kai Exp $
+/* $Id: tpam.h,v 1.1.2.1 2001/11/20 14:19:38 kai Exp $
  *
  * Turbo PAM ISDN driver for Linux. (Kernel Driver)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/isdn.h linux/include/linux/isdn.h
--- linux-2.4.16/include/linux/isdn.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/isdn.h	Sun Dec  9 19:23:11 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.111.6.9 2001/09/23 22:25:05 kai Exp $
+/* $Id: isdn.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/isdn_divertif.h linux/include/linux/isdn_divertif.h
--- linux-2.4.16/include/linux/isdn_divertif.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/isdn_divertif.h	Sun Dec  9 19:23:11 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_divertif.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $
+/* $Id: isdn_divertif.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
  *
  * Header for the diversion supplementary interface for i4l.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/isdn_lzscomp.h linux/include/linux/isdn_lzscomp.h
--- linux-2.4.16/include/linux/isdn_lzscomp.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/isdn_lzscomp.h	Sun Dec  9 19:23:11 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_lzscomp.h,v 1.1.10.1 2001/09/23 22:25:05 kai Exp $
+/* $Id: isdn_lzscomp.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
  *
  * Header for isdn_lzscomp.c
  * Concentrated here to not mess up half a dozen kernel headers with code
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/isdnif.h linux/include/linux/isdnif.h
--- linux-2.4.16/include/linux/isdnif.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/isdnif.h	Sun Dec  9 19:23:11 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.37.6.6 2001/09/23 22:25:05 kai Exp $
+/* $Id: isdnif.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
  *
  * Linux ISDN subsystem
  * Definition of the interface between the subsystem and its low-level drivers.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/jbd.h linux/include/linux/jbd.h
--- linux-2.4.16/include/linux/jbd.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/jbd.h	Thu Dec  6 20:42:51 2001
@@ -221,7 +221,7 @@
 #endif
 
 #else
-#define J_ASSERT(assert)
+#define J_ASSERT(assert)	do { } while (0)
 #endif		/* JBD_ASSERTIONS */
 
 enum jbd_state_bits {
@@ -564,7 +564,7 @@
 
 /* Log buffer allocation */
 extern struct journal_head * journal_get_descriptor_buffer(journal_t *);
-extern unsigned long journal_next_log_block(journal_t *);
+int journal_next_log_block(journal_t *, unsigned long *);
 
 /* Commit management */
 extern void journal_commit_transaction(journal_t *);
@@ -664,15 +664,16 @@
 extern void	   journal_destroy    (journal_t *);
 extern int	   journal_recover    (journal_t *journal);
 extern int	   journal_wipe       (journal_t *, int);
-extern int	   journal_skip_recovery (journal_t *);
-extern void	   journal_update_superblock (journal_t *, int);
-extern void	   __journal_abort      (journal_t *);
+extern int	   journal_skip_recovery	(journal_t *);
+extern void	   journal_update_superblock	(journal_t *, int);
+extern void	   __journal_abort_hard	(journal_t *);
+extern void	   __journal_abort_soft	(journal_t *, int);
 extern void	   journal_abort      (journal_t *, int);
 extern int	   journal_errno      (journal_t *);
 extern void	   journal_ack_err    (journal_t *);
 extern int	   journal_clear_err  (journal_t *);
-extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr);
-extern int	    journal_force_commit(journal_t *journal);
+extern int	   journal_bmap(journal_t *, unsigned long, unsigned long *);
+extern int	   journal_force_commit(journal_t *);
 
 /*
  * journal_head management
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/list.h linux/include/linux/list.h
--- linux-2.4.16/include/linux/list.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/list.h	Fri Dec  7 19:36:53 2001
@@ -162,6 +162,16 @@
 	for (pos = (head)->next, n = pos->next; pos != (head); \
 		pos = n, n = pos->next)
 
+/**
+ * list_for_each_prev	-	iterate over a list in reverse order
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+        	pos = pos->prev, prefetch(pos->prev))
+        	
+
 #endif /* __KERNEL__ || _LVM_H_INCLUDE */
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/mm.h linux/include/linux/mm.h
--- linux-2.4.16/include/linux/mm.h	Mon Nov 26 10:35:11 2001
+++ linux/include/linux/mm.h	Thu Dec  6 19:57:21 2001
@@ -422,6 +422,9 @@
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+
 /*
  * On a two-level page table, this ends up being trivial. Thus the
  * inlining and the symmetry break with pte_alloc() that does all
@@ -557,11 +560,13 @@
 	 * before relocating the vma range ourself.
 	 */
 	address &= PAGE_MASK;
+ 	spin_lock(&vma->vm_mm->page_table_lock);
 	grow = (vma->vm_start - address) >> PAGE_SHIFT;
 	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
-	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
+	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) {
+		spin_unlock(&vma->vm_mm->page_table_lock);
 		return -ENOMEM;
-	spin_lock(&vma->vm_mm->page_table_lock);
+	}
 	vma->vm_start = address;
 	vma->vm_pgoff -= grow;
 	vma->vm_mm->total_vm += grow;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/netlink.h linux/include/linux/netlink.h
--- linux-2.4.16/include/linux/netlink.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/netlink.h	Wed Dec  5 16:36:05 2001
@@ -5,6 +5,7 @@
 #define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
+#define NETLINK_TCPDIAG		4	/* TCP socket monitoring			*/
 #define NETLINK_ARPD		8
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- linux-2.4.16/include/linux/nfs_fs.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/nfs_fs.h	Fri Dec  7 19:34:54 2001
@@ -16,6 +16,7 @@
 
 #include <linux/sunrpc/debug.h>
 #include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
 
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
@@ -331,6 +332,29 @@
 		wait_event(wq, condition);				\
 	__retval;							\
 })
+
+#ifdef CONFIG_NFS_V3
+
+#define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
+static inline int
+nfs_async_handle_jukebox(struct rpc_task *task)
+{
+	if (task->tk_status != -EJUKEBOX)
+		return 0;
+	task->tk_status = 0;
+	rpc_restart_call(task);
+	rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
+	return 1;
+}
+
+#else
+
+static inline int
+nfs_async_handle_jukebox(struct rpc_task *task)
+{
+	return 0;
+}
+#endif /* CONFIG_NFS_V3 */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- linux-2.4.16/include/linux/pci_ids.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/pci_ids.h	Tue Dec  4 19:28:22 2001
@@ -1229,6 +1229,7 @@
 #define PCI_DEVICE_ID_AVM_B1		0x0700
 #define PCI_DEVICE_ID_AVM_C4		0x0800
 #define PCI_DEVICE_ID_AVM_A1		0x0a00
+#define PCI_DEVICE_ID_AVM_A1_V2		0x0e00
 #define PCI_DEVICE_ID_AVM_C2		0x1100
 #define PCI_DEVICE_ID_AVM_T1		0x1200
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- linux-2.4.16/include/linux/reiserfs_fs.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/reiserfs_fs.h	Thu Dec  6 16:21:36 2001
@@ -52,48 +52,17 @@
 
 */
 
-				/* Vladimir, what is the story with
-                                   new_get_new_buffer nowadays?  I
-                                   want a complete explanation written
-                                   here. */
-
-/* NEW_GET_NEW_BUFFER will try to allocate new blocks better */
-/*#define NEW_GET_NEW_BUFFER*/
-#define OLD_GET_NEW_BUFFER
-
-				/* Vladimir, what about this one too? */
-/* if this is undefined, all inode changes get into stat data immediately, if it can be found in RAM */
-#define DIRTY_LATER
-
-/* enable journalling */
-#define ENABLE_JOURNAL
-
 #define USE_INODE_GENERATION_COUNTER
 
-
-#ifdef __KERNEL__
-
-/* #define REISERFS_CHECK */
-
 #define REISERFS_PREALLOCATE
-#endif
 #define PREALLOCATION_SIZE 8
 
-/* if this is undefined, all inode changes get into stat data
-   immediately, if it can be found in RAM */
-#define DIRTY_LATER
-
-
-/*#define READ_LOCK_REISERFS*/
-
-
 /* n must be power of 2 */
 #define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
 
 // to be ok for alpha and others we have to align structures to 8 byte
 // boundary.
 // FIXME: do not change 4 by anything else: there is code which relies on that
-				/* what 4? -Hans */
 #define ROUND_UP(x) _ROUND_UP(x,8LL)
 
 /* debug levels.  Right now, CONFIG_REISERFS_CHECK means print all debug
@@ -148,22 +117,17 @@
 		      strlen ( reiser2fs_super_magic_string)));
 }
 
-				/* ReiserFS leaves the first 64k unused,
-                                   so that partition labels have enough
-                                   space.  If someone wants to write a
-                                   fancy bootloader that needs more than
-                                   64k, let us know, and this will be
-                                   increased in size.  This number must
-                                   be larger than than the largest block
-                                   size on any platform, or code will
-                                   break.  -Hans */
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+   enough space.  If someone wants to write a fancy bootloader that
+   needs more than 64k, let us know, and this will be increased in size.
+   This number must be larger than than the largest block size on any
+   platform, or code will break.  -Hans */
 #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
 #define REISERFS_FIRST_BLOCK unused_define
 
 /* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
 #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
 
-
 // reiserfs internal error code (used by search_by_key adn fix_nodes))
 #define CARRY_ON      0
 #define REPEAT_SEARCH -1
@@ -172,53 +136,54 @@
 #define NO_BALANCING_NEEDED  (-4)
 #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
 
-//#define SCHEDULE_OCCURRED  	1
-//#define PATH_INCORRECT    	2
-
-//#define NO_DISK_SPACE        (-1)
-
-
-
 typedef unsigned long b_blocknr_t;
 typedef __u32 unp_t;
 
-				/* who is responsible for this
-                                   completely uncommented struct? */
 struct unfm_nodeinfo {
-				/* This is what? */
     unp_t unfm_nodenum;
-				/* now this I know what it is, and
-                                   most of the people on our project
-                                   know what it is, but I bet nobody
-                                   new I hire will have a clue. */
     unsigned short unfm_freespace;
 };
 
 
-/* when reiserfs_file_write is called with a byte count >= MIN_PACK_ON_CLOSE,
-** it sets the inode to pack on close, and when extending the file, will only
-** use unformatted nodes.
-**
-** This is a big speed up for the journal, which is badly hurt by direct->indirect
-** conversions (they must be logged).
-*/
-#define MIN_PACK_ON_CLOSE		512
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
 
-// this says about version of all items (but stat data) the object
-// consists of
-#define inode_items_version(inode) ((inode)->u.reiserfs_i.i_version)
-
-
-  /* This is an aggressive tail suppression policy, I am hoping it
-     improves our benchmarks. The principle behind it is that
-     percentage space saving is what matters, not absolute space
-     saving.  This is non-intuitive, but it helps to understand it if
-     you consider that the cost to access 4 blocks is not much more
-     than the cost to access 1 block, if you have to do a seek and
-     rotate.  A tail risks a non-linear disk access that is
-     significant as a percentage of total time cost for a 4 block file
-     and saves an amount of space that is less significant as a
-     percentage of space, or so goes the hypothesis.  -Hans */
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    (((inode)->u.reiserfs_i.i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version )                           \
+         ({ if((version)==KEY_FORMAT_3_6)                                      \
+                (inode)->u.reiserfs_i.i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                (inode)->u.reiserfs_i.i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    (((inode)->u.reiserfs_i.i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version)                                   \
+         ({ if((version)==STAT_DATA_V2)                                        \
+                (inode)->u.reiserfs_i.i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                (inode)->u.reiserfs_i.i_flags &= ~i_stat_data_version_mask; })
+
+/* This is an aggressive tail suppression policy, I am hoping it
+   improves our benchmarks. The principle behind it is that percentage
+   space saving is what matters, not absolute space saving.  This is
+   non-intuitive, but it helps to understand it if you consider that the
+   cost to access 4 blocks is not much more than the cost to access 1
+   block, if you have to do a seek and rotate.  A tail risks a
+   non-linear disk access that is significant as a percentage of total
+   time cost for a 4 block file and saves an amount of space that is
+   less significant as a percentage of space, or so goes the hypothesis.
+   -Hans */
 #define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \
 (\
   (!(n_tail_size)) || \
@@ -246,21 +211,6 @@
 /***************************************************************************/
 
 //
-// we do support for old format of reiserfs: the problem is to
-// distinuquish keys with 32 bit offset and keys with 60 bit ones. On
-// leaf level we use ih_version of struct item_head (was
-// ih_reserved). For all old items it is set to 0
-// (ITEM_VERSION_1). For new items it is ITEM_VERSION_2. On internal
-// levels we have to know version of item key belongs to.
-//
-#define ITEM_VERSION_1 0
-#define ITEM_VERSION_2 1
-
-
-/* loff_t - long long */
-
-
-//
 // directories use this key as well as old files
 //
 struct offset_v1 {
@@ -341,18 +291,11 @@
 		       indirect2direct conversion */
 };
 
-
-
-
-
-
-
- /* Our function for comparing keys can compare keys of different
-    lengths.  It takes as a parameter the length of the keys it is to
-    compare.  These defines are used in determining what is to be
-    passed to it as that parameter. */
+/* Our function for comparing keys can compare keys of different
+   lengths.  It takes as a parameter the length of the keys it is to
+   compare.  These defines are used in determining what is to be passed
+   to it as that parameter. */
 #define REISERFS_FULL_KEY_LEN     4
-
 #define REISERFS_SHORT_KEY_LEN    2
 
 /* The result of the key compare */
@@ -362,7 +305,6 @@
 #define KEY_FOUND 1
 #define KEY_NOT_FOUND 0
 
-
 #define KEY_SIZE (sizeof(struct key))
 #define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
 
@@ -387,8 +329,6 @@
 #define GOTO_PREVIOUS_ITEM 2
 #define NAME_FOUND_INVISIBLE 3
 
-
-
 /*  Everything in the filesystem is stored as a set of items.  The
     item head contains the key of the item, its free space (for
     indirect items) and specifies the location of the item itself
@@ -396,37 +336,28 @@
 
 struct item_head
 {
-  struct key ih_key; 	/* Everything in the tree is found by searching for it based on its key.*/
-
-				/* This is bloat, this should be part
-                                   of the item not the item
-                                   header. -Hans */
-  union {
-    __u16 ih_free_space_reserved; /* The free space in the last unformatted node of an indirect item if this
-				     is an indirect item.  This equals 0xFFFF iff this is a direct item or
-				     stat data item. Note that the key, not this field, is used to determine
-				     the item type, and thus which field this union contains. */
-    __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory
-				      entries in the directory item. */
-  } __attribute__ ((__packed__)) u;
-  __u16 ih_item_len;           /* total size of the item body */
-  __u16 ih_item_location;      /* an offset to the item body within the block */
-				/* I thought we were going to use this
-                                   for having lots of item types? Why
-                                   don't you use this for item type
-                                   not item version.  That is how you
-                                   talked me into this field a year
-                                   ago, remember?  I am still not
-                                   convinced it needs to be 16 bits
-                                   (for at least many years), but at
-                                   least I can sympathize with that
-                                   hope. Change the name from version
-                                   to type, and tell people not to use
-                                   FFFF in case 16 bits is someday too
-                                   small and needs to be extended:-). */
-  __u16 ih_version;	       /* 0 for all old items, 2 for new
-                                  ones. Highest bit is set by fsck
-                                  temporary, cleaned after all done */
+	/* Everything in the tree is found by searching for it based on
+	 * its key.*/
+	struct key ih_key; 	
+	union {
+		/* The free space in the last unformatted node of an
+		   indirect item if this is an indirect item.  This
+		   equals 0xFFFF iff this is a direct item or stat data
+		   item. Note that the key, not this field, is used to
+		   determine the item type, and thus which field this
+		   union contains. */
+		__u16 ih_free_space_reserved; 
+		/* Iff this is a directory item, this field equals the
+		   number of directory entries in the directory item. */
+		__u16 ih_entry_count; 
+	} __attribute__ ((__packed__)) u;
+	__u16 ih_item_len;           /* total size of the item body */
+	__u16 ih_item_location;      /* an offset to the item body
+				      * within the block */
+	__u16 ih_version;	     /* 0 for all old items, 2 for new
+					ones. Highest bit is set by fsck
+					temporary, cleaned after all
+					done */
 } __attribute__ ((__packed__));
 /* size of item header     */
 #define IH_SIZE (sizeof(struct item_head))
@@ -446,8 +377,8 @@
 
 #define unreachable_item(ih) (ih_version(ih) & (1 << 15))
 
-#define get_ih_free_space(ih) (ih_version (ih) == ITEM_VERSION_2 ? 0 : ih_free_space (ih))
-#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == ITEM_VERSION_2) ? 0 : (val)))
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val)))
 
 /* these operate on indirect items, where you've got an array of ints
 ** at a possibly unaligned location.  These are a noop on ia32
@@ -476,6 +407,9 @@
 #define V1_DIRENTRY_UNIQUENESS 500
 #define V1_ANY_UNIQUENESS 555 // FIXME: comment is required
 
+extern void reiserfs_warning (const char * fmt, ...);
+/* __attribute__( ( format ( printf, 1, 2 ) ) ); */
+
 //
 // here are conversion routines
 //
@@ -487,14 +421,11 @@
     case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT;
     case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT;
     case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY;
+    default:
+	    reiserfs_warning( "vs-500: unknown uniqueness %d\n", uniqueness);
+	case V1_ANY_UNIQUENESS:
+	    return TYPE_ANY;
     }
-/*
-    if (uniqueness != V1_ANY_UNIQUENESS) {
-	printk ("uniqueness %d\n", uniqueness);
-	BUG (); 
-    }
-*/
-    return TYPE_ANY;
 }
 
 static inline __u32 type2uniqueness (int type) CONSTF;
@@ -505,15 +436,13 @@
     case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS;
     case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS;
     case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS;
+    default:
+	    reiserfs_warning( "vs-501: unknown type %d\n", type);
+	case TYPE_ANY:
+	    return V1_ANY_UNIQUENESS;
     }
-    /*
-    if (type != TYPE_ANY)
-	BUG ();
-    */
-    return V1_ANY_UNIQUENESS;
 }
 
-
 //
 // key is pointer to on disk key which is stored in le, result is cpu,
 // there is no way to get version of object from key, so, provide
@@ -521,7 +450,7 @@
 //
 static inline loff_t le_key_k_offset (int version, const struct key * key)
 {
-    return (version == ITEM_VERSION_1) ?
+    return (version == KEY_FORMAT_3_5) ?
         le32_to_cpu( key->u.k_offset_v1.k_offset ) :
 	offset_v2_k_offset( &(key->u.k_offset_v2) );
 }
@@ -533,7 +462,7 @@
 
 static inline loff_t le_key_k_type (int version, const struct key * key)
 {
-    return (version == ITEM_VERSION_1) ?
+    return (version == KEY_FORMAT_3_5) ?
         uniqueness2type( le32_to_cpu( key->u.k_offset_v1.k_uniqueness)) :
 	offset_v2_k_type( &(key->u.k_offset_v2) );
 }
@@ -546,20 +475,21 @@
 
 static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
 {
-    (version == ITEM_VERSION_1) ?
+    (version == KEY_FORMAT_3_5) ?
         (key->u.k_offset_v1.k_offset = cpu_to_le32 (offset)) : /* jdm check */
 	(set_offset_v2_k_offset( &(key->u.k_offset_v2), offset ));
 }
+
+
 static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
 {
     set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset);
 }
 
 
-
 static inline void set_le_key_k_type (int version, struct key * key, int type)
 {
-    (version == ITEM_VERSION_1) ?
+    (version == KEY_FORMAT_3_5) ?
         (key->u.k_offset_v1.k_uniqueness = cpu_to_le32(type2uniqueness(type))):
 	(set_offset_v2_k_type( &(key->u.k_offset_v2), type ));
 }
@@ -589,21 +519,21 @@
 //
 static inline loff_t cpu_key_k_offset (const struct cpu_key * key)
 {
-    return (key->version == ITEM_VERSION_1) ?
+    return (key->version == KEY_FORMAT_3_5) ?
         key->on_disk_key.u.k_offset_v1.k_offset :
 	key->on_disk_key.u.k_offset_v2.k_offset;
 }
 
 static inline loff_t cpu_key_k_type (const struct cpu_key * key)
 {
-    return (key->version == ITEM_VERSION_1) ?
+    return (key->version == KEY_FORMAT_3_5) ?
         uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
 	key->on_disk_key.u.k_offset_v2.k_type;
 }
 
 static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
 {
-    (key->version == ITEM_VERSION_1) ?
+    (key->version == KEY_FORMAT_3_5) ?
         (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
 	(key->on_disk_key.u.k_offset_v2.k_offset = offset);
 }
@@ -611,14 +541,15 @@
 
 static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
 {
-    (key->version == ITEM_VERSION_1) ?
+    (key->version == KEY_FORMAT_3_5) ?
         (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)):
 	(key->on_disk_key.u.k_offset_v2.k_type = type);
 }
 
+
 static inline void cpu_key_k_offset_dec (struct cpu_key * key)
 {
-    if (key->version == ITEM_VERSION_1)
+    if (key->version == KEY_FORMAT_3_5)
 	key->on_disk_key.u.k_offset_v1.k_offset --;
     else
 	key->on_disk_key.u.k_offset_v2.k_offset --;
@@ -761,7 +692,7 @@
 } __attribute__ ((__packed__));
 
 #define SD_V1_SIZE              (sizeof(struct stat_data_v1))
-#define stat_data_v1(ih)        (ih_version (ih) == ITEM_VERSION_1)
+#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
 #define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
 #define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
 #define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
@@ -815,11 +746,11 @@
   } __attribute__ ((__packed__)) u;
 } __attribute__ ((__packed__));
 //
-// this is 40 bytes long
+// this is 44 bytes long
 //
 #define SD_SIZE (sizeof(struct stat_data))
 #define SD_V2_SIZE              SD_SIZE
-#define stat_data_v2(ih)        (ih_version (ih) == ITEM_VERSION_2)
+#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
 #define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
 #define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
 /* sd_reserved */
@@ -949,76 +880,10 @@
 #define de_visible(deh)	    	    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
 #define de_hidden(deh)	    	    !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
 
-/* compose directory item containing "." and ".." entries (entries are
-   not aligned to 4 byte boundary) */
-/* the last four params are LE */
-static inline void make_empty_dir_item_v1 (char * body,
-                                           __u32 dirid, __u32 objid,
-					   __u32 par_dirid, __u32 par_objid)
-{
-    struct reiserfs_de_head * deh;
-
-    memset (body, 0, EMPTY_DIR_SIZE_V1);
-    deh = (struct reiserfs_de_head *)body;
-    
-    /* direntry header of "." */
-    put_deh_offset( &(deh[0]), DOT_OFFSET );
-    /* these two are from make_le_item_head, and are are LE */
-    deh[0].deh_dir_id = dirid;
-    deh[0].deh_objectid = objid;
-    deh[0].deh_state = 0; /* Endian safe if 0 */
-    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." ));
-    mark_de_visible(&(deh[0]));
-  
-    /* direntry header of ".." */
-    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET);
-    /* key of ".." for the root directory */
-    /* these two are from the inode, and are are LE */
-    deh[1].deh_dir_id = par_dirid;
-    deh[1].deh_objectid = par_objid;
-    deh[1].deh_state = 0; /* Endian safe if 0 */
-    put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) );
-    mark_de_visible(&(deh[1]));
-
-    /* copy ".." and "." */
-    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
-    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
-}
-
-/* compose directory item containing "." and ".." entries */
-static inline void make_empty_dir_item (char * body,
-                                        __u32 dirid, __u32 objid,
-					__u32 par_dirid, __u32 par_objid)
-{
-    struct reiserfs_de_head * deh;
-
-    memset (body, 0, EMPTY_DIR_SIZE);
-    deh = (struct reiserfs_de_head *)body;
-    
-    /* direntry header of "." */
-    put_deh_offset( &(deh[0]), DOT_OFFSET );
-    /* these two are from make_le_item_head, and are are LE */
-    deh[0].deh_dir_id = dirid;
-    deh[0].deh_objectid = objid;
-    deh[0].deh_state = 0; /* Endian safe if 0 */
-    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) );
-    mark_de_visible(&(deh[0]));
-  
-    /* direntry header of ".." */
-    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET );
-    /* key of ".." for the root directory */
-    /* these two are from the inode, and are are LE */
-    deh[1].deh_dir_id = par_dirid;
-    deh[1].deh_objectid = par_objid;
-    deh[1].deh_state = 0; /* Endian safe if 0 */
-    put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) );
-    mark_de_visible(&(deh[1]));
-
-    /* copy ".." and "." */
-    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
-    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
-}
-
+extern void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+				    __u32 par_dirid, __u32 par_objid);
+extern void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+				 __u32 par_dirid, __u32 par_objid);
 
 /* array of the entry headers */
  /* get item body */
@@ -1059,13 +924,9 @@
 // two entries per block (at least)
 //#define REISERFS_MAX_NAME_LEN(block_size) 
 //((block_size - BLKH_SIZE - IH_SIZE - DEH_SIZE * 2) / 2)
-
-// two entries per block (at least)
 #define REISERFS_MAX_NAME_LEN(block_size) 255
 
 
-
-
 /* this structure is used for operations on directory entries. It is
    not a disk structure. */
 /* When reiserfs_find_entry or search_by_entry_key find directory
@@ -1258,23 +1119,17 @@
 
 // in in-core inode key is stored on le form
 #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
-//#define mark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted),1))
-//#define unmark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted), 0))
-//#define is_tail_converted(inode) (atomic_read(&((inode)->u.reiserfs_i.i_converted)))
-
-
 
 #define MAX_UL_INT 0xffffffff
 #define MAX_INT    0x7ffffff
 #define MAX_US_INT 0xffff
 
-///#define TOO_LONG_LENGTH		(~0ULL)
-
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
 #define U32_MAX (~(__u32)0)
+
 static inline loff_t max_reiserfs_offset (const struct inode * inode)
 {
-    if (inode_items_version (inode) == ITEM_VERSION_1)
+    if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
 	return (loff_t)U32_MAX;
 
     return (loff_t)((~(__u64)0) >> 4);
@@ -1307,13 +1162,6 @@
 /*                  FIXATE NODES                                           */
 /***************************************************************************/
 
-//#define VI_TYPE_STAT_DATA 1
-//#define VI_TYPE_DIRECT 2
-//#define VI_TYPE_INDIRECT 4
-//#define VI_TYPE_DIRECTORY 8
-//#define VI_TYPE_FIRST_DIRECTORY_ITEM 16
-//#define VI_TYPE_INSERTED_DIRECTORY_ITEM 32
-
 #define VI_TYPE_LEFT_MERGEABLE 1
 #define VI_TYPE_RIGHT_MERGEABLE 2
 
@@ -1536,11 +1384,7 @@
 
 #define COMP_KEYS comp_keys
 #define COMP_SHORT_KEYS comp_short_keys
-#define keys_of_same_object comp_short_keys
-
-/*#define COMP_KEYS(p_s_key1, p_s_key2)		comp_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))
-#define COMP_SHORT_KEYS(p_s_key1, p_s_key2)	comp_short_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))*/
-
+/*#define keys_of_same_object comp_short_keys*/
 
 /* number of blocks pointed to by the indirect item */
 #define I_UNFM_NUM(p_s_ih)	( ih_item_len(p_s_ih) / UNFM_P_SIZE )
@@ -1675,18 +1519,12 @@
 int journal_mark_freed(struct reiserfs_transaction_handle *, struct super_block *, unsigned long blocknr) ;
 int push_journal_writer(char *w) ;
 int pop_journal_writer(int windex) ;
-int journal_lock_dobalance(struct super_block *p_s_sb) ;
-int journal_unlock_dobalance(struct super_block *p_s_sb) ;
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
 int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
 int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
-int journal_join(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
 struct super_block *reiserfs_get_super(kdev_t dev) ;
 void flush_async_commits(struct super_block *p_s_sb) ;
 
-int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) ;
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) ;
-
 int buffer_journaled(const struct buffer_head *bh) ;
 int mark_buffer_journal_new(struct buffer_head *bh) ;
 int reiserfs_sync_all_buffers(kdev_t dev, int wait) ;
@@ -1725,6 +1563,10 @@
   return 0 ;
 }
 
+void add_save_link (struct reiserfs_transaction_handle * th,
+					struct inode * inode, int truncate);
+void remove_save_link (struct inode * inode, int truncate);
+
 /* objectid.c */
 __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th);
 void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, __u32 objectid_to_release);
@@ -1762,16 +1604,16 @@
     
     type = offset_v2_k_type( &(key->u.k_offset_v2));
     if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY)
-	return ITEM_VERSION_1;
+	return KEY_FORMAT_3_5;
 
-    return ITEM_VERSION_2;
+    return KEY_FORMAT_3_6;
 	
 }
 
 
 static inline void copy_key (struct key *to, const struct key *from)
 {
-  memcpy (to, from, KEY_SIZE);
+    memcpy (to, from, KEY_SIZE);
 }
 
 
@@ -1815,17 +1657,12 @@
 			  struct inode * inode, 
 			  struct buffer_head  * p_s_un_bh);
 
-
+void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
+                                                                struct key * key);
 void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
 void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, 
 			   struct  inode * p_s_inode, struct page *, 
 			   int update_timestamps);
-//
-//void lock_inode_to_convert (struct inode * p_s_inode);
-//void unlock_inode_after_convert (struct inode * p_s_inode);
-//void increment_i_read_sync_counter (struct inode * p_s_inode);
-//void decrement_i_read_sync_counter (struct inode * p_s_inode);
-
 
 #define block_size(inode) ((inode)->i_sb->s_blocksize)
 #define file_size(inode) ((inode)->i_size)
@@ -1834,19 +1671,18 @@
 #define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
 !STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode)))
 
-/*
-int get_buffer_by_range (struct super_block * p_s_sb, struct key * p_s_range_begin, struct key * p_s_range_end, 
-			 struct buffer_head ** pp_s_buf, unsigned long * p_n_objectid);
-int get_buffers_from_range (struct super_block * p_s_sb, struct key * p_s_range_start, struct key * p_s_range_end, 
-                            struct buffer_head ** p_s_range_buffers,
-			    int n_max_nr_buffers_to_return);
-*/
-
 void padd_item (char * item, int total_length, int length);
 
-
 /* inode.c */
 
+void reiserfs_read_inode (struct inode * inode) ;
+void reiserfs_read_inode2(struct inode * inode, void *p) ;
+void reiserfs_delete_inode (struct inode * inode);
+void reiserfs_write_inode (struct inode * inode, int) ;
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data,
+									 int len, int fhtype, int parent);
+int reiserfs_dentry_to_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent);
+
 int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
 void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
 void make_cpu_key (struct cpu_key * cpu_key, const struct inode * inode, loff_t offset,
@@ -1854,24 +1690,9 @@
 void make_le_item_head (struct item_head * ih, const struct cpu_key * key, 
 			int version,
 			loff_t offset, int type, int length, int entry_count);
-/*void store_key (struct key * key);
-void forget_key (struct key * key);*/
-int reiserfs_get_block (struct inode * inode, long block,
-			struct buffer_head * bh_result, int create);
 struct inode * reiserfs_iget (struct super_block * s, 
 			      const struct cpu_key * key);
-void reiserfs_read_inode (struct inode * inode) ;
-void reiserfs_read_inode2(struct inode * inode, void *p) ;
-void reiserfs_delete_inode (struct inode * inode);
-extern int reiserfs_notify_change(struct dentry * dentry, struct iattr * attr);
-void reiserfs_write_inode (struct inode * inode, int) ;
 
-/* nfsd support functions */
-struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
-int reiserfs_dentry_to_fh(struct dentry *, __u32 *fh, int *lenp, int need_parent);
-
-/* we don't mark inodes dirty, we just log them */
-void reiserfs_dirty_inode (struct inode * inode) ;
 
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
 				   const struct inode * dir, int mode, 
@@ -1879,36 +1700,12 @@
 				   struct dentry *dentry, struct inode *inode, int * err);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
 void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);
-int reiserfs_inode_setattr(struct dentry *,  struct iattr * attr);
 
 /* namei.c */
 inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de);
 int search_by_entry_key (struct super_block * sb, const struct cpu_key * key, 
 			 struct path * path, 
 			 struct reiserfs_dir_entry * de);
-struct dentry * reiserfs_lookup (struct inode * dir, struct dentry *dentry);
-int reiserfs_create (struct inode * dir, struct dentry *dentry,	int mode);
-int reiserfs_mknod (struct inode * dir_inode, struct dentry *dentry, int mode, int rdev);
-int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode);
-int reiserfs_rmdir (struct inode * dir,	struct dentry *dentry);
-int reiserfs_unlink (struct inode * dir, struct dentry *dentry);
-int reiserfs_symlink (struct inode * dir, struct dentry *dentry, const char * symname);
-int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry);
-int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry);
-
-/* super.c */
-inline void reiserfs_mark_buffer_dirty (struct buffer_head * bh, int flag);
-inline void reiserfs_mark_buffer_clean (struct buffer_head * bh);
-void reiserfs_write_super (struct super_block * s);
-void reiserfs_put_super (struct super_block * s);
-int reiserfs_remount (struct super_block * s, int * flags, char * data);
-/*int read_super_block (struct super_block * s, int size);
-int read_bitmaps (struct super_block * s);
-int read_old_bitmaps (struct super_block * s);
-int read_old_super_block (struct super_block * s, int size);*/
-struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent);
-int reiserfs_statfs (struct super_block * s, struct statfs * buf);
-
 /* procfs.c */
 
 #if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
@@ -2006,8 +1803,6 @@
 /* prints.c */
 void reiserfs_panic (struct super_block * s, const char * fmt, ...)
 __attribute__ ( ( noreturn ) );/* __attribute__( ( format ( printf, 2, 3 ) ) ) */
-void reiserfs_warning (const char * fmt, ...);
-/* __attribute__( ( format ( printf, 1, 2 ) ) ); */
 void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...);
 /* __attribute__( ( format ( printf, 3, 4 ) ) ); */
 void print_virtual_node (struct virtual_node * vn);
@@ -2099,83 +1894,6 @@
 #define reiserfs_test_and_clear_le_bit ext2_clear_bit
 #define reiserfs_test_le_bit           ext2_test_bit
 #define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit
-
-
-//
-// this was totally copied from from linux's
-// find_first_zero_bit and changed a bit
-//
-
-#ifdef __i386__
-
-static __inline__ int 
-find_first_nonzero_bit(const void * addr, unsigned size) {
-  int res;
-  int __d0;
-  void *__d1;
-
-
-  if (!size) {
-    return (0);
-  }
-  __asm__ __volatile__ (
-	  "cld\n\t"
-	  "xorl %%eax,%%eax\n\t"
-	  "repe; scasl\n\t"
-	  "je 1f\n\t"
-	  "movl -4(%%edi),%%eax\n\t"
-	  "subl $4, %%edi\n\t"
-	  "bsfl %%eax,%%eax\n\t"
-	  "1:\tsubl %%edx,%%edi\n\t"
-	  "shll $3,%%edi\n\t"
-	  "addl %%edi,%%eax"
-	  :"=a" (res),
-	  "=c"(__d0), "=D"(__d1)
-	  :"1" ((size + 31) >> 5), "d" (addr), "2" (addr));
-  return (res);
-}
-
-#else /* __i386__ */
-
-static __inline__ int find_next_nonzero_bit(const void * addr, unsigned size, 
-											unsigned offset)
-{
-	unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		/* set to zero first offset bits */
-		tmp &= ~(~0UL >> (32-offset));
-		if (size < 32)
-			goto found_first;
-		if (tmp != 0U)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0U)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-found_first:
-found_middle:
-	return result + ffs(tmp);
-}
-
-#define find_first_nonzero_bit(addr,size) find_next_nonzero_bit((addr), (size), 0)
-
-#endif /* 0 */
 
 /* sometimes reiserfs_truncate may require to allocate few new blocks
    to perform indirect2direct conversion. People probably used to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h
--- linux-2.4.16/include/linux/reiserfs_fs_i.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/reiserfs_fs_i.h	Thu Dec  6 16:21:36 2001
@@ -3,50 +3,47 @@
 
 #include <linux/list.h>
 
+/** bitmasks for i_flags field in reiserfs-specific part of inode */
+typedef enum {
+    /** this says what format of key do all items (but stat data) of
+	an object have.  If this is set, that format is 3.6 otherwise
+	- 3.5 */
+    i_item_key_version_mask    =  0x0001,
+    /** If this is unset, object has 3.5 stat data, otherwise, it has
+	3.6 stat data with 64bit size, 32bit nlink etc. */
+    i_stat_data_version_mask   =  0x0002,
+    /** file might need tail packing on close */
+    i_pack_on_close_mask       =  0x0004,
+    /** don't pack tail of file */
+    i_nopack_mask              =  0x0008,
+    /** If those is set, "safe link" was created for this file during
+	truncate or unlink. Safe link is used to avoid leakage of disk
+	space on crash with some files open, but unlinked. */
+    i_link_saved_unlink_mask   =  0x0010,
+    i_link_saved_truncate_mask =  0x0020
+} reiserfs_inode_flags;
+
+
 struct reiserfs_inode_info {
-  __u32 i_key [4];/* key is still 4 32 bit integers */
+    __u32 i_key [4];/* key is still 4 32 bit integers */
   
-				/* this comment will be totally
-                                   cryptic to readers not familiar
-                                   with 3.5/3.6 format conversion, and
-                                   it does not consider that that 3.6
-                                   might not be the last version */
-  int i_version;  // this says whether file is old or new
-
-  int i_pack_on_close ; // file might need tail packing on close 
-
-  __u32 i_first_direct_byte; // offset of first byte stored in direct item.
-
-				/* My guess is this contains the first
-                                   unused block of a sequence of
-                                   blocks plus the length of the
-                                   sequence, which I think is always
-                                   at least two at the time of the
-                                   preallocation.  I really prefer
-                                   allocate on flush conceptually.....
-
-				   You know, it really annoys me when
-				   code is this badly commented that I
-				   have to guess what it does.
-				   Neither I nor anyone else has time
-				   for guessing what your
-				   datastructures mean.  -Hans */
-  //For preallocation
-  int i_prealloc_block;
-  int i_prealloc_count;
-  struct list_head i_prealloc_list;	/* per-transaction list of inodes which
-				 * have preallocated blocks */
-				/* I regret that you think the below
-                                   is a comment you should make.... -Hans */
-  //nopack-attribute
-  int nopack;
+    /** transient inode flags that are never stored on disk. Bitmasks
+	for this field are defined above. */
+    __u32 i_flags;
+
+    __u32 i_first_direct_byte; // offset of first byte stored in direct item.
+
+    int i_prealloc_block; /* first unused block of a sequence of unused blocks */
+    int i_prealloc_count; /* length of that sequence */
+    struct list_head i_prealloc_list;	/* per-transaction list of inodes which
+					 * have preallocated blocks */
   
-  /* we use these for fsync or O_SYNC to decide which transaction needs
-  ** to be committed in order for this inode to be properly flushed
-  */
-  unsigned long i_trans_id ;
-  unsigned long i_trans_index ;
+    /* we use these for fsync or O_SYNC to decide which transaction
+    ** needs to be committed in order for this inode to be properly
+    ** flushed */
+    unsigned long i_trans_id ;
+    unsigned long i_trans_index ;
 };
 
-
 #endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- linux-2.4.16/include/linux/reiserfs_fs_sb.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/reiserfs_fs_sb.h	Tue Dec  4 19:25:31 2001
@@ -420,6 +420,10 @@
     int s_bmaps_without_search;
     int s_direct2indirect;
     int s_indirect2direct;
+	/* set up when it's ok for reiserfs_read_inode2() to read from
+	   disk inode with nlink==0. Currently this is only used during
+	   finish_unfinished() processing at mount time */
+    int s_is_unlinked_ok;
     reiserfs_proc_info_data_t s_proc_info_data;
     struct proc_dir_entry *procdir;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- linux-2.4.16/include/linux/rtnetlink.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/rtnetlink.h	Wed Dec  5 16:36:05 2001
@@ -546,7 +546,6 @@
 
 extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
 
-#ifdef CONFIG_RTNETLINK
 extern struct sock *rtnl;
 
 struct rtnetlink_link
@@ -568,12 +567,6 @@
 
 extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
 
-#else
-
-#define rtmsg_ifinfo(a,b,c) do { } while (0)
-
-#endif
-
 extern struct semaphore rtnl_sem;
 
 #define rtnl_exlock()		do { } while(0)
@@ -583,14 +576,10 @@
 #define rtnl_shlock()		down(&rtnl_sem)
 #define rtnl_shlock_nowait()	down_trylock(&rtnl_sem)
 
-#ifndef CONFIG_RTNETLINK
-#define rtnl_shunlock()	up(&rtnl_sem)
-#else
 #define rtnl_shunlock()	do { up(&rtnl_sem); \
 		             if (rtnl && rtnl->receive_queue.qlen) \
 				     rtnl->data_ready(rtnl, 0); \
 		        } while(0)
-#endif
 
 extern void rtnl_lock(void);
 extern void rtnl_unlock(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/shmem_fs.h linux/include/linux/shmem_fs.h
--- linux-2.4.16/include/linux/shmem_fs.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/shmem_fs.h	Thu Dec  6 14:31:00 2001
@@ -11,7 +11,7 @@
  * swapper address space.
  *
  * We have to move it here, since not every user of fs.h is including
- * mm.h, but m.h is including fs.h via sched .h :-/
+ * mm.h, but mm.h is including fs.h via sched .h :-/
  */
 typedef struct {
 	unsigned long val;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/slab.h linux/include/linux/slab.h
--- linux-2.4.16/include/linux/slab.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/slab.h	Tue Dec  4 19:25:31 2001
@@ -38,6 +38,7 @@
 #define	SLAB_NO_REAP		0x00001000UL	/* never reap from the cache */
 #define	SLAB_HWCACHE_ALIGN	0x00002000UL	/* align objs on a h/w cache lines */
 #define SLAB_CACHE_DMA		0x00004000UL	/* use GFP_DMA memory */
+#define SLAB_MUST_HWCACHE_ALIGN	0x00008000UL	/* force alignment */
 
 /* flags passed to a constructor func */
 #define	SLAB_CTOR_CONSTRUCTOR	0x001UL		/* if not set, then deconstructor */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/socket.h linux/include/linux/socket.h
--- linux-2.4.16/include/linux/socket.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/socket.h	Thu Dec  6 15:47:36 2001
@@ -156,6 +156,7 @@
 #define AF_IRDA		23	/* IRDA sockets			*/
 #define AF_PPPOX	24	/* PPPoX sockets		*/
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
+#define AF_LLC		26	/* Linux LLC			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
 #define AF_MAX		32	/* For now.. */
 
@@ -187,6 +188,7 @@
 #define PF_IRDA		AF_IRDA
 #define PF_PPPOX	AF_PPPOX
 #define PF_WANPIPE	AF_WANPIPE
+#define PF_LLC		AF_LLC
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #define PF_MAX		AF_MAX
 
@@ -237,6 +239,8 @@
 #define SOL_ATM		264	/* ATM layer (cell level) */
 #define SOL_AAL		265	/* ATM Adaption Layer (packet level) */
 #define SOL_IRDA        266
+#define SOL_NETBEUI	267
+#define SOL_LLC		268
 
 /* IPX options */
 #define IPX_TYPE	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/tcp_diag.h linux/include/linux/tcp_diag.h
--- linux-2.4.16/include/linux/tcp_diag.h	Thu Jan  1 00:00:00 1970
+++ linux/include/linux/tcp_diag.h	Thu Dec  6 17:41:02 2001
@@ -0,0 +1,116 @@
+#ifndef _TCP_DIAG_H_
+#define _TCP_DIAG_H_ 1
+
+/* Just some random number */
+#define TCPDIAG_GETSOCK 18
+
+/* Socket identity */
+struct tcpdiag_sockid
+{
+	__u16	tcpdiag_sport;
+	__u16	tcpdiag_dport;
+	__u32	tcpdiag_src[4];
+	__u32	tcpdiag_dst[4];
+	__u32	tcpdiag_if;
+	__u32	tcpdiag_cookie[2];
+#define TCPDIAG_NOCOOKIE (~0U)
+};
+
+/* Request structure */
+
+struct tcpdiagreq
+{
+	__u8	tcpdiag_family;		/* Family of addresses. */
+	__u8	tcpdiag_src_len;
+	__u8	tcpdiag_dst_len;
+	__u8	tcpdiag_ext;		/* Query extended information */
+
+	struct tcpdiag_sockid id;
+
+	__u32	tcpdiag_states;		/* States to dump */
+	__u32	tcpdiag_dbs;		/* Tables to dump (NI) */
+};
+
+enum
+{
+	TCPDIAG_REQ_NONE,
+	TCPDIAG_REQ_BYTECODE,
+};
+
+#define TCPDIAG_REQ_MAX TCPDIAG_REQ_BYTECODE
+
+/* Bytecode is sequence of 4 byte commands followed by variable arguments.
+ * All the commands identified by "code" are conditional jumps forward:
+ * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
+ * length of the command and its arguments.
+ */
+ 
+struct tcpdiag_bc_op
+{
+	unsigned char	code;
+	unsigned char	yes;
+	unsigned short	no;
+};
+
+enum
+{
+	TCPDIAG_BC_NOP,
+	TCPDIAG_BC_JMP,
+	TCPDIAG_BC_S_GE,
+	TCPDIAG_BC_S_LE,
+	TCPDIAG_BC_D_GE,
+	TCPDIAG_BC_D_LE,
+	TCPDIAG_BC_AUTO,
+	TCPDIAG_BC_S_COND,
+	TCPDIAG_BC_D_COND,
+};
+
+struct tcpdiag_hostcond
+{
+	__u8	family;
+	__u8	prefix_len;
+	int	port;
+	__u32	addr[0];
+};
+
+/* Base info structure. It contains socket identity (addrs/ports/cookie)
+ * and, alas, the information shown by netstat. */
+struct tcpdiagmsg
+{
+	__u8	tcpdiag_family;
+	__u8	tcpdiag_state;
+	__u8	tcpdiag_timer;
+	__u8	tcpdiag_retrans;
+
+	struct tcpdiag_sockid id;
+
+	__u32	tcpdiag_expires;
+	__u32	tcpdiag_rqueue;
+	__u32	tcpdiag_wqueue;
+	__u32	tcpdiag_uid;
+	__u32	tcpdiag_inode;
+};
+
+/* Extensions */
+
+enum
+{
+	TCPDIAG_NONE,
+	TCPDIAG_MEMINFO,
+	TCPDIAG_INFO,
+};
+
+#define TCPDIAG_MAX TCPDIAG_INFO
+
+
+/* TCPDIAG_MEM */
+
+struct tcpdiag_meminfo
+{
+	__u32	tcpdiag_rmem;
+	__u32	tcpdiag_wmem;
+	__u32	tcpdiag_fmem;
+	__u32	tcpdiag_tmem;
+};
+
+#endif /* _TCP_DIAG_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/linux/usb.h linux/include/linux/usb.h
--- linux-2.4.16/include/linux/usb.h	Mon Nov 26 10:35:00 2001
+++ linux/include/linux/usb.h	Tue Dec  4 19:41:21 2001
@@ -11,10 +11,13 @@
 #define USB_CLASS_COMM			2
 #define USB_CLASS_HID			3
 #define USB_CLASS_PHYSICAL		5
+#define USB_CLASS_STILL_IMAGE		6
 #define USB_CLASS_PRINTER		7
 #define USB_CLASS_MASS_STORAGE		8
 #define USB_CLASS_HUB			9
-#define USB_CLASS_DATA			10
+#define USB_CLASS_CDC_DATA		0x0a
+#define USB_CLASS_CSCID		0x0b /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC		0x0d /* content security */
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/net/dn_fib.h linux/include/net/dn_fib.h
--- linux-2.4.16/include/net/dn_fib.h	Mon Nov 26 10:35:00 2001
+++ linux/include/net/dn_fib.h	Wed Dec  5 16:36:05 2001
@@ -113,9 +113,7 @@
 	int (*get_info)(struct dn_fib_table *table, char *buf,
 			int first, int count);
 #endif /* CONFIG_PROC_FS */
-#ifdef CONFIG_RTNETLINK
 	int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
 
 	unsigned char data[0];
 };
@@ -163,7 +161,6 @@
 /*
  * rtnetlink interface
  */
-#ifdef CONFIG_RTNETLINK
 extern int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb);
@@ -171,7 +168,6 @@
 extern int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
 
 #define DN_NUM_TABLES 255
 #define DN_MIN_TABLE 1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/net/irda/irlmp.h linux/include/net/irda/irlmp.h
--- linux-2.4.16/include/net/irda/irlmp.h	Mon Nov 26 10:35:00 2001
+++ linux/include/net/irda/irlmp.h	Tue Dec  4 19:25:31 2001
@@ -264,4 +264,16 @@
 	return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap);
 }
 
+/* After doing a irlmp_dup(), this get one of the two socket back into
+ * a state where it's waiting incomming connections.
+ * Note : this can be used *only* if the socket is not yet connected
+ * (i.e. NO irlmp_connect_response() done on this socket).
+ * - Jean II */
+static inline void irlmp_listen(struct lsap_cb *self)
+{
+	self->dlsap_sel = LSAP_ANY;
+	self->lap = NULL;
+	self->lsap_state = LSAP_DISCONNECTED;
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/net/irda/irttp.h linux/include/net/irda/irttp.h
--- linux-2.4.16/include/net/irda/irttp.h	Mon Nov 26 10:35:00 2001
+++ linux/include/net/irda/irttp.h	Tue Dec  4 19:25:31 2001
@@ -148,6 +148,17 @@
 	return self->max_seg_size;
 }
 
+/* After doing a irttp_dup(), this get one of the two socket back into
+ * a state where it's waiting incomming connections.
+ * Note : this can be used *only* if the socket is not yet connected
+ * (i.e. NO irttp_connect_response() done on this socket).
+ * - Jean II */
+static inline void irttp_listen(struct tsap_cb *self)
+{
+	irlmp_listen(self->lsap);
+	self->dtsap_sel = LSAP_ANY;
+}
+
 extern struct irttp_cb *irttp;
 
 #endif /* IRTTP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/net/sock.h linux/include/net/sock.h
--- linux-2.4.16/include/net/sock.h	Mon Nov 26 10:35:00 2001
+++ linux/include/net/sock.h	Wed Dec  5 16:36:05 2001
@@ -643,9 +643,7 @@
 #if defined(CONFIG_PPPOE) || defined(CONFIG_PPPOE_MODULE)
 		struct pppox_opt	*pppox;
 #endif
-#ifdef CONFIG_NETLINK
 		struct netlink_opt	*af_netlink;
-#endif
 #if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
 		struct econet_opt	*af_econet;
 #endif
@@ -828,6 +826,11 @@
 						     unsigned long size,
 						     int noblock,
 						     int *errcode);
+extern struct sk_buff 		*sock_alloc_send_pskb(struct sock *sk,
+						      unsigned long header_len,
+						      unsigned long data_len,
+						      int noblock,
+						      int *errcode);
 extern void *sock_kmalloc(struct sock *sk, int size, int priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h
--- linux-2.4.16/include/pcmcia/ciscode.h	Mon Nov 26 10:35:00 2001
+++ linux/include/pcmcia/ciscode.h	Tue Dec  4 19:25:31 2001
@@ -1,5 +1,5 @@
 /*
- * ciscode.h 1.45 2000/08/12 02:08:23
+ * ciscode.h 1.48 2001/08/24 12:16:12
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -16,8 +16,8 @@
  * 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
+ * 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
@@ -104,6 +104,8 @@
 #define PRODID_QUATECH_DUAL_RS232	0x0012
 #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
 #define PRODID_QUATECH_QUAD_RS232	0x001b
+#define PRODID_QUATECH_DUAL_RS422	0x000e
+#define PRODID_QUATECH_QUAD_RS422	0x0045
 
 #define MANFID_SMC			0x0108
 #define PRODID_SMC_ETHER		0x0105
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/pcmcia/cs.h linux/include/pcmcia/cs.h
--- linux-2.4.16/include/pcmcia/cs.h	Mon Nov 26 10:35:00 2001
+++ linux/include/pcmcia/cs.h	Tue Dec  4 19:25:31 2001
@@ -1,5 +1,5 @@
 /*
- * cs.h 1.71 2000/08/29 00:54:20
+ * cs.h 1.74 2001/10/04 03:15:22
  *
  * 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
@@ -16,8 +16,8 @@
  * 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
+ * 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
@@ -181,6 +181,7 @@
 #define INT_MEMORY		0x01
 #define INT_MEMORY_AND_IO	0x02
 #define INT_CARDBUS		0x04
+#define INT_ZOOMED_VIDEO	0x08
 
 /* For RequestIO and ReleaseIO */
 typedef struct io_req_t {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/include/scsi/sg.h linux/include/scsi/sg.h
--- linux-2.4.16/include/scsi/sg.h	Mon Nov 26 10:35:00 2001
+++ linux/include/scsi/sg.h	Mon Dec 10 18:21:40 2001
@@ -11,9 +11,21 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2001 Douglas Gilbert
 
-    Version: 3.1.20 (20010814)
+    Version: 3.1.22 (20011208)
     This version is for 2.4 series kernels.
 
+    Changes since 3.1.21 (20011029)
+    	- add support for SG_FLAG_MMAP_IO [permit mmap() on sg devices]
+    	- update documentation pointers in this header
+    	- put KERNEL_VERSION macros around code that breaks early 2.4 series
+    	- fix use count for multiple queued requests on closed fd
+    	- switch back to alloc_kiovec()
+    Changes since 3.1.20 (20010814)
+	- use alloc_kiovec_sz() to speed dio [set num_buffer_heads==0]
+	- changes to cope with larger scatter gather element sizes
+	- clean up some printk()s
+	- add MODULE_LICENSE("GPL") [in a 3.1.20 subversion]
+	- fix race around generic_unplug_device() [in a 3.1.20 subversion]
     Changes since 3.1.19 (20010623)
 	- add SG_GET_ACCESS_COUNT ioctl 
 	- make open() increment and close() decrement access_count
@@ -33,56 +45,57 @@
 Map of SG verions to the Linux kernels in which they appear:
        ----------        ----------------------------------
        original          all kernels < 2.2.6
-       2.1.38            2.2.16
-       2.1.39            2.2.17 - 2.2.19
+       2.1.40            2.2.20
        3.0.x             optional version 3 sg driver for 2.2 series
-       3.1.17            2.4.0 ++
+       3.1.17++          2.4.0++
 
 Major new features in SG 3.x driver (cf SG 2.x drivers)
 	- SG_IO ioctl() combines function if write() and read()
 	- new interface (sg_io_hdr_t) but still supports old interface
-	- scatter/gather in user space and direct IO supported
+	- scatter/gather in user space, direct IO, and mmap supported
 
- The term "indirect IO" refers a method by which data is DMAed into kernel
- buffers from the hardware and afterwards is transferred into the user
- space (or vice versa if you are writing). Transfer speeds of up to 20 to
- 30MBytes/sec have been measured using indirect IO. For faster throughputs
- "direct IO" which cuts out the double handling of data is required.
- Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels
- and requires the use of the new interface.
-
- Requests for direct IO with the new interface will automatically fall back
- to indirect IO mode if they cannot be fulfilled. An example of such a case
- is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of
- memory due to the architecture of ISA. The 'info' field in the new
- interface indicates whether a direct or indirect data transfer took place.
-
- Obtaining memory for the kernel buffers used in indirect IO is done by
- first checking if the "reserved buffer" for the current file descriptor
- is available and large enough. If these conditions are _not_ met then
- kernel memory is obtained on a per SCSI command basis. This corresponds
- to a write(), read() sequence or a SG_IO ioctl() call. Further, the
- kernel memory that is suitable for DMA may be constrained by the
- architecture of the SCSI adapter (e.g. ISA adapters).
+ The normal action of this driver is to use the adapter (HBA) driver to DMA
+ data into kernel buffers and then use the CPU to copy the data into the 
+ user space (vice versa for writes). That is called "indirect" IO due to 
+ the double handling of data. There are two methods offered to remove the
+ redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and 
+ 2) using the mmap() system call to map the reserve buffer (this driver has 
+ one reserve buffer per fd) into the user space. Both have their advantages.
+ In terms of absolute speed mmap() is faster. If speed is not a concern, 
+ indirect IO should be fine. Read the documentation for more information.
 
  ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
          needed. That pseudo file's content is defaulted to 0. **
+ 
+ Historical note: this SCSI pass-through driver has been known as "sg" for 
+ a decade. In broader kernel discussions "sg" is used to refer to scatter
+ gather techniques. The context should clarify which "sg" is referred to.
 
  Documentation
  =============
- A web site for SG device drivers can be found at:
+ A web site for the SG device driver can be found at:
 	http://www.torque.net/sg  [alternatively check the MAINTAINERS file]
- The main documents are still based on 2.x versions:
+ The documentation for the sg version 3 driver can be found at:
+ 	http://www.torque.net/sg/p/sg_v3_ho.html
+ This is a rendering from DocBook source [change the extension to "sgml"
+ or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+
+ The older, version 2 documents discuss the original sg interface in detail:
 	http://www.torque.net/sg/p/scsi-generic.txt
 	http://www.torque.net/sg/p/scsi-generic_long.txt
- Documentation on the changes and additions in 3.x version of the sg driver
- can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
  A version of this document (potentially out of date) may also be found in
  the kernel source tree, probably at:
         /usr/src/linux/Documentation/scsi-generic.txt .
- Utility and test programs are available at the sg web site.
+
+ Utility and test programs are available at the sg web site. They are 
+ bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
+ lk 2.4 series).
+
+ There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
+ 	http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
 */
 
+
 /* New interface introduced in the 3.x SG drivers follows */
 
 typedef struct sg_iovec /* same structure as used by readv() Linux system */
@@ -120,19 +133,20 @@
 } sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
 /* Use negative values to flag difference from original sg_header structure */
-#define SG_DXFER_NONE -1        /* e.g. a SCSI Test Unit Ready command */
-#define SG_DXFER_TO_DEV -2      /* e.g. a SCSI WRITE command */
-#define SG_DXFER_FROM_DEV -3    /* e.g. a SCSI READ command */
-#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the
+#define SG_DXFER_NONE (-1)      /* e.g. a SCSI Test Unit Ready command */
+#define SG_DXFER_TO_DEV (-2)    /* e.g. a SCSI WRITE command */
+#define SG_DXFER_FROM_DEV (-3)  /* e.g. a SCSI READ command */
+#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
 				   additional property than during indirect
 				   IO the user buffer is copied into the
 				   kernel buffers before the transfer */
-#define SG_DXFER_UNKNOWN -5     /* Unknown data direction */
+#define SG_DXFER_UNKNOWN (-5)   /* Unknown data direction */
 
 /* following flag values can be "or"-ed together */
 #define SG_FLAG_DIRECT_IO 1     /* default is indirect IO */
-#define SG_FLAG_LUN_INHIBIT 2   /* default is to put device's lun into */
-				/* the 2nd byte of SCSI command */
+#define SG_FLAG_LUN_INHIBIT 2   /* default is overwrite lun in SCSI */
+				/* command block (when <= SCSI_2) */
+#define SG_FLAG_MMAP_IO 4       /* request memory mapped IO */
 #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
 				/* user space (debug indirect IO) */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/init/main.c linux/init/main.c
--- linux-2.4.16/init/main.c	Mon Nov 26 10:35:00 2001
+++ linux/init/main.c	Tue Dec  4 19:25:31 2001
@@ -591,6 +591,8 @@
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
+	pgtable_cache_init();
+
 	mempages = num_physpages;
 
 	fork_init(mempages);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/ipc/shm.c linux/ipc/shm.c
--- linux-2.4.16/ipc/shm.c	Mon Nov 26 10:35:01 2001
+++ linux/ipc/shm.c	Sun Dec  9 18:07:37 2001
@@ -569,6 +569,7 @@
 {
 	struct shmid_kernel *shp;
 	unsigned long addr;
+	unsigned long size;
 	struct file * file;
 	int    err;
 	unsigned long flags;
@@ -588,8 +589,12 @@
 				return -EINVAL;
 		}
 		flags = MAP_SHARED | MAP_FIXED;
-	} else
+	} else {
+		if ((shmflg & SHM_REMAP))
+			return -EINVAL;
+
 		flags = MAP_SHARED;
+	}
 
 	if (shmflg & SHM_RDONLY) {
 		prot = PROT_READ;
@@ -603,7 +608,7 @@
 
 	/*
 	 * We cannot rely on the fs check since SYSV IPC does have an
-	 * aditional creator id...
+	 * additional creator id...
 	 */
 	shp = shm_lock(shmid);
 	if(shp == NULL)
@@ -618,11 +623,27 @@
 		return -EACCES;
 	}
 	file = shp->shm_file;
+	size = file->f_dentry->d_inode->i_size;
 	shp->shm_nattch++;
 	shm_unlock(shmid);
 
 	down_write(&current->mm->mmap_sem);
-	user_addr = (void *) do_mmap (file, addr, file->f_dentry->d_inode->i_size, prot, flags, 0);
+	if (addr && !(shmflg & SHM_REMAP)) {
+		user_addr = ERR_PTR(-EINVAL);
+		if (find_vma_intersection(current->mm, addr, addr + size))
+			goto invalid;
+		/*
+		 * If shm segment goes below stack, make sure there is some
+		 * space left for the stack to grow (at least 4 pages).
+		 */
+		if (addr < current->mm->start_stack &&
+		    addr > current->mm->start_stack - size - PAGE_SIZE * 5)
+			goto invalid;
+	}
+		
+	user_addr = (void*) do_mmap (file, addr, size, prot, flags, 0);
+
+invalid:
 	up_write(&current->mm->mmap_sem);
 
 	down (&shm_ids.sem);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/exec_domain.c linux/kernel/exec_domain.c
--- linux-2.4.16/kernel/exec_domain.c	Mon Nov 26 10:35:00 2001
+++ linux/kernel/exec_domain.c	Tue Dec  4 19:25:31 2001
@@ -102,7 +102,7 @@
 	}
 #endif
 
-	ep = NULL;
+	ep = &default_exec_domain;
 out:
 	read_unlock(&exec_domains_lock);
 	return (ep);
@@ -162,8 +162,6 @@
 	struct exec_domain	*ep, *oep;
 
 	ep = lookup_exec_domain(personality);
-	if (ep == NULL)
-		return -EINVAL;
 	if (ep == current->exec_domain) {
 		current->personality = personality;
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.16/kernel/ksyms.c	Mon Nov 26 10:35:00 2001
+++ linux/kernel/ksyms.c	Tue Dec  4 19:25:31 2001
@@ -46,6 +46,7 @@
 #include <linux/tty.h>
 #include <linux/in6.h>
 #include <linux/completion.h>
+#include <linux/seq_file.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -476,6 +477,12 @@
 EXPORT_SYMBOL(reparent_to_init);
 EXPORT_SYMBOL(daemonize);
 EXPORT_SYMBOL(csum_partial); /* for networking and md */
+EXPORT_SYMBOL(seq_escape);
+EXPORT_SYMBOL(seq_printf);
+EXPORT_SYMBOL(seq_open);
+EXPORT_SYMBOL(seq_release);
+EXPORT_SYMBOL(seq_read);
+EXPORT_SYMBOL(seq_lseek);
 
 /* Program loader interfaces */
 EXPORT_SYMBOL(setup_arg_pages);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/printk.c linux/kernel/printk.c
--- linux-2.4.16/kernel/printk.c	Mon Nov 26 10:35:00 2001
+++ linux/kernel/printk.c	Mon Dec 10 17:05:24 2001
@@ -38,6 +38,10 @@
 
 #define LOG_BUF_MASK	(LOG_BUF_LEN-1)
 
+#ifndef arch_consoles_callable
+#define arch_consoles_callable() (1)
+#endif
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -438,6 +442,14 @@
 			log_level_unknown = 1;
 	}
 
+	if (!arch_consoles_callable()) {
+		/*
+		 * On some architectures, the consoles are not usable
+		 * on secondary CPUs early in the boot process.
+		 */
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+		goto out;
+	}
 	if (!down_trylock(&console_sem)) {
 		/*
 		 * We own the drivers.  We can drop the spinlock and let
@@ -454,6 +466,7 @@
 		 */
 		spin_unlock_irqrestore(&logbuf_lock, flags);
 	}
+out:
 	return printed_len;
 }
 EXPORT_SYMBOL(printk);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/ptrace.c linux/kernel/ptrace.c
--- linux-2.4.16/kernel/ptrace.c	Mon Nov 26 10:35:00 2001
+++ linux/kernel/ptrace.c	Thu Dec  6 19:57:21 2001
@@ -121,119 +121,17 @@
 }
 
 /*
- * Access another process' address space, one page at a time.
+ * Access another process' address space.
+ * Source/target buffer must be kernel space, 
+ * Do not walk the page table directly, use get_user_pages
  */
-static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-	char *maddr; 
-	struct page *page;
-
-repeat:
-	spin_lock(&mm->page_table_lock);
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir))
-		goto fault_in_page;
-	if (pgd_bad(*pgdir))
-		goto bad_pgd;
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle))
-		goto fault_in_page;
-	if (pmd_bad(*pgmiddle))
-		goto bad_pmd;
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable))
-		goto fault_in_page;
-	if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
-		goto fault_in_page;
-	page = pte_page(*pgtable);
-
-	/* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */
-	if (page != ZERO_PAGE(addr) || write) {
-		if ((!VALID_PAGE(page)) || PageReserved(page)) {
-			spin_unlock(&mm->page_table_lock);
-			return 0;
-		}
-	}
-	get_page(page);
-	spin_unlock(&mm->page_table_lock);
-	flush_cache_page(vma, addr);
-
-	if (write) {
-		maddr = kmap(page);
-		memcpy(maddr + (addr & ~PAGE_MASK), buf, len);
-		flush_page_to_ram(page);
-		flush_icache_page(vma, page);
-		kunmap(page);
-	} else {
-		maddr = kmap(page);
-		memcpy(buf, maddr + (addr & ~PAGE_MASK), len);
-		flush_page_to_ram(page);
-		kunmap(page);
-	}
-	put_page(page);
-	return len;
-
-fault_in_page:
-	spin_unlock(&mm->page_table_lock);
-	/* -1: out of memory. 0 - unmapped page */
-	if (handle_mm_fault(mm, vma, addr, write) > 0)
-		goto repeat;
-	return 0;
-
-bad_pgd:
-	spin_unlock(&mm->page_table_lock);
-	pgd_ERROR(*pgdir);
-	return 0;
-
-bad_pmd:
-	spin_unlock(&mm->page_table_lock);
-	pmd_ERROR(*pgmiddle);
-	return 0;
-}
-
-static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
-{
-	int copied = 0;
-
-	for (;;) {
-		unsigned long offset = addr & ~PAGE_MASK;
-		int this_len = PAGE_SIZE - offset;
-		int retval;
-
-		if (this_len > len)
-			this_len = len;
-		retval = access_one_page(mm, vma, addr, buf, this_len, write);
-		copied += retval;
-		if (retval != this_len)
-			break;
-
-		len -= retval;
-		if (!len)
-			break;
-
-		addr += retval;
-		buf += retval;
-
-		if (addr < vma->vm_end)
-			continue;	
-		if (!vma->vm_next)
-			break;
-		if (vma->vm_next->vm_start != vma->vm_end)
-			break;
-	
-		vma = vma->vm_next;
-	}
-	return copied;
-}
 
 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
 {
-	int copied;
 	struct mm_struct *mm;
-	struct vm_area_struct * vma;
+	struct vm_area_struct *vma;
+	struct page *page;
+	void *old_buf = buf;
 
 	/* Worry about races with exit() */
 	task_lock(tsk);
@@ -245,14 +143,41 @@
 		return 0;
 
 	down_read(&mm->mmap_sem);
-	vma = find_extend_vma(mm, addr);
-	copied = 0;
-	if (vma)
-		copied = access_mm(mm, vma, addr, buf, len, write);
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		int bytes, ret, offset;
+		void *maddr;
+
+		ret = get_user_pages(current, mm, addr, 1,
+				write, 1, &page, &vma);
+		if (ret <= 0)
+			break;
+
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
 
+		flush_cache_page(vma, addr);
+
+		maddr = kmap(page);
+		if (write) {
+			memcpy(maddr + offset, buf, bytes);
+			flush_page_to_ram(page);
+			flush_icache_page(vma, page);
+		} else {
+			memcpy(buf, maddr + offset, bytes);
+			flush_page_to_ram(page);
+		}
+		kunmap(page);
+		put_page(page);
+		len -= bytes;
+		buf += bytes;
+	}
 	up_read(&mm->mmap_sem);
 	mmput(mm);
-	return copied;
+	
+	return buf - old_buf;
 }
 
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/sched.c linux/kernel/sched.c
--- linux-2.4.16/kernel/sched.c	Mon Nov 26 10:35:00 2001
+++ linux/kernel/sched.c	Thu Dec  6 16:32:26 2001
@@ -262,6 +262,21 @@
 		 * a problem.
 		 */
 		if (tsk == idle_task(cpu)) {
+#if defined(__i386__) && defined(CONFIG_SMP)
+                        /*
+			 * Check if two siblings are idle in the same
+			 * physical package. Use them if found.
+			 */
+			if (smp_num_siblings == 2) {
+				if (cpu_curr(cpu_sibling_map[cpu]) == 
+			            idle_task(cpu_sibling_map[cpu])) {
+					oldest_idle = last_schedule(cpu);
+					target_tsk = tsk;
+					break;
+				}
+				
+                        }
+#endif		
 			if (last_schedule(cpu) < oldest_idle) {
 				oldest_idle = last_schedule(cpu);
 				target_tsk = tsk;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.4.16/kernel/sysctl.c	Mon Nov 26 10:35:11 2001
+++ linux/kernel/sysctl.c	Mon Dec 10 18:41:29 2001
@@ -45,7 +45,8 @@
 extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern int sysctl_overcommit_memory;
 extern int max_threads;
-extern int nr_queued_signals, max_queued_signals;
+extern atomic_t nr_queued_signals;
+extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
 extern int cad_pid;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/kernel/time.c linux/kernel/time.c
--- linux-2.4.16/kernel/time.c	Mon Nov 26 10:35:00 2001
+++ linux/kernel/time.c	Wed Dec  5 16:57:21 2001
@@ -70,11 +70,11 @@
  */
 asmlinkage long sys_time(int * tloc)
 {
-	int i;
+	struct timeval now; 
+	int i; 
 
-	/* SMP: This is fairly trivial. We grab CURRENT_TIME and 
-	   stuff it to user space. No side effects */
-	i = CURRENT_TIME;
+	do_gettimeofday(&now);
+	i = now.tv_sec;
 	if (tloc) {
 		if (put_user(i,tloc))
 			i = -EFAULT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/bootmem.c linux/mm/bootmem.c
--- linux-2.4.16/mm/bootmem.c	Mon Nov 26 10:35:00 2001
+++ linux/mm/bootmem.c	Thu Dec  6 15:41:46 2001
@@ -154,6 +154,12 @@
 	if (align & (align-1))
 		BUG();
 
+	offset = 0;
+	if (align &&
+	    (bdata->node_boot_start & (align - 1UL)) != 0)
+		offset = (align - (bdata->node_boot_start & (align - 1UL)));
+	offset >>= PAGE_SHIFT;
+
 	/*
 	 * We try to allocate bootmem pages above 'goal'
 	 * first, then we try to allocate lower pages.
@@ -165,6 +171,7 @@
 		preferred = 0;
 
 	preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
+	preferred += offset;
 	areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
 	incr = align >> PAGE_SHIFT ? : 1;
 
@@ -184,7 +191,7 @@
 	fail_block:;
 	}
 	if (preferred) {
-		preferred = 0;
+		preferred = offset;
 		goto restart_scan;
 	}
 	return NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/filemap.c linux/mm/filemap.c
--- linux-2.4.16/mm/filemap.c	Mon Nov 26 10:35:11 2001
+++ linux/mm/filemap.c	Fri Dec  7 18:58:23 2001
@@ -53,7 +53,7 @@
 EXPORT_SYMBOL(vm_min_readahead);
 
 
-spinlock_t pagecache_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+spinlock_t pagecache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 /*
  * NOTE: to avoid deadlocking you must never acquire the pagemap_lru_lock 
  *	with the pagecache_lock held.
@@ -63,7 +63,7 @@
  *		pagemap_lru_lock ->
  *			pagecache_lock
  */
-spinlock_t pagemap_lru_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+spinlock_t pagemap_lru_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 #define CLUSTER_PAGES		(1 << page_cluster)
 #define CLUSTER_OFFSET(x)	(((x) >> page_cluster) << page_cluster)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/highmem.c linux/mm/highmem.c
--- linux-2.4.16/mm/highmem.c	Mon Nov 26 10:35:00 2001
+++ linux/mm/highmem.c	Fri Dec  7 18:58:23 2001
@@ -32,7 +32,7 @@
  */
 static int pkmap_count[LAST_PKMAP];
 static unsigned int last_pkmap_nr;
-static spinlock_t kmap_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t kmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 pte_t * pkmap_page_table;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/memory.c linux/mm/memory.c
--- linux-2.4.16/mm/memory.c	Mon Nov 26 10:35:00 2001
+++ linux/mm/memory.c	Fri Dec  7 18:48:52 2001
@@ -397,17 +397,16 @@
 	spin_unlock(&mm->page_table_lock);
 }
 
-
 /*
  * Do a quick page-table lookup for a single page. 
  */
-static struct page * follow_page(unsigned long address, int write) 
+static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write) 
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *ptep, pte;
 
-	pgd = pgd_offset(current->mm, address);
+	pgd = pgd_offset(mm, address);
 	if (pgd_none(*pgd) || pgd_bad(*pgd))
 		goto out;
 
@@ -443,21 +442,74 @@
 	return page;
 }
 
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas)
+{
+	int i = 0;
+
+	do {
+		struct vm_area_struct *	vma;
+
+		vma = find_extend_vma(mm, start);
+
+		if ( !vma ||
+		    (!force &&
+		     	((write && (!(vma->vm_flags & VM_WRITE))) ||
+		    	 (!write && (!(vma->vm_flags & VM_READ))) ) )) {
+			if (i) return i;
+			return -EFAULT;
+		}
+
+		spin_lock(&mm->page_table_lock);
+		do {
+			struct page *map;
+			while (!(map = follow_page(mm, start, write))) {
+				spin_unlock(&mm->page_table_lock);
+				switch (handle_mm_fault(mm, vma, start, write)) {
+				case 1:
+					tsk->min_flt++;
+					break;
+				case 2:
+					tsk->maj_flt++;
+					break;
+				case 0:
+					if (i) return i;
+					return -EFAULT;
+				default:
+					if (i) return i;
+					return -ENOMEM;
+				}
+				spin_lock(&mm->page_table_lock);
+			}
+			if (pages) {
+				pages[i] = get_page_map(map);
+				/* FIXME: call the correct function,
+				 * depending on the type of the found page
+				 */
+				if (pages[i])
+					page_cache_get(pages[i]);
+			}
+			if (vmas)
+				vmas[i] = vma;
+			i++;
+			start += PAGE_SIZE;
+			len--;
+		} while(len && start < vma->vm_end);
+		spin_unlock(&mm->page_table_lock);
+	} while(len);
+	return i;
+}
+
 /*
  * Force in an entire range of pages from the current process's user VA,
  * and pin them in physical memory.  
  */
-
 #define dprintk(x...)
+
 int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
 {
-	unsigned long		ptr, end;
-	int			err;
+	int pgcount, err;
 	struct mm_struct *	mm;
-	struct vm_area_struct *	vma = 0;
-	struct page *		map;
-	int			i;
-	int			datain = (rw == READ);
 	
 	/* Make sure the iobuf is not already mapped somewhere. */
 	if (iobuf->nr_pages)
@@ -466,79 +518,37 @@
 	mm = current->mm;
 	dprintk ("map_user_kiobuf: begin\n");
 	
-	ptr = va & PAGE_MASK;
-	end = (va + len + PAGE_SIZE - 1) & PAGE_MASK;
-	err = expand_kiobuf(iobuf, (end - ptr) >> PAGE_SHIFT);
+	pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE;
+	/* mapping 0 bytes is not permitted */
+	if (!pgcount) BUG();
+	err = expand_kiobuf(iobuf, pgcount);
 	if (err)
 		return err;
 
-	down_read(&mm->mmap_sem);
-
-	err = -EFAULT;
 	iobuf->locked = 0;
-	iobuf->offset = va & ~PAGE_MASK;
+	iobuf->offset = va & (PAGE_SIZE-1);
 	iobuf->length = len;
 	
-	i = 0;
-	
-	/* 
-	 * First of all, try to fault in all of the necessary pages
-	 */
-	while (ptr < end) {
-		if (!vma || ptr >= vma->vm_end) {
-			vma = find_vma(current->mm, ptr);
-			if (!vma) 
-				goto out_unlock;
-			if (vma->vm_start > ptr) {
-				if (!(vma->vm_flags & VM_GROWSDOWN))
-					goto out_unlock;
-				if (expand_stack(vma, ptr))
-					goto out_unlock;
-			}
-			if (((datain) && (!(vma->vm_flags & VM_WRITE))) ||
-					(!(vma->vm_flags & VM_READ))) {
-				err = -EACCES;
-				goto out_unlock;
-			}
-		}
-		spin_lock(&mm->page_table_lock);
-		while (!(map = follow_page(ptr, datain))) {
-			int ret;
-
-			spin_unlock(&mm->page_table_lock);
-			ret = handle_mm_fault(current->mm, vma, ptr, datain);
-			if (ret <= 0) {
-				if (!ret)
-					goto out_unlock;
-				else {
-					err = -ENOMEM;
-					goto out_unlock;
-				}
-			}
-			spin_lock(&mm->page_table_lock);
-		}			
-		map = get_page_map(map);
-		if (map) {
-			flush_dcache_page(map);
-			page_cache_get(map);
-		} else
-			printk (KERN_INFO "Mapped page missing [%d]\n", i);
-		spin_unlock(&mm->page_table_lock);
-		iobuf->maplist[i] = map;
-		iobuf->nr_pages = ++i;
-		
-		ptr += PAGE_SIZE;
-	}
-
+	/* Try to fault in all of the necessary pages */
+	down_read(&mm->mmap_sem);
+	/* rw==READ means read from disk, write into memory area */
+	err = get_user_pages(current, mm, va, pgcount,
+			(rw==READ), 0, iobuf->maplist, NULL);
 	up_read(&mm->mmap_sem);
+	if (err < 0) {
+		unmap_kiobuf(iobuf);
+		dprintk ("map_user_kiobuf: end %d\n", err);
+		return err;
+	}
+	iobuf->nr_pages = err;
+	while (pgcount--) {
+		/* FIXME: flush superflous for rw==READ,
+		 * probably wrong function for rw==WRITE
+		 */
+		flush_dcache_page(iobuf->maplist[pgcount]);
+	}
 	dprintk ("map_user_kiobuf: end OK\n");
 	return 0;
-
- out_unlock:
-	up_read(&mm->mmap_sem);
-	unmap_kiobuf(iobuf);
-	dprintk ("map_user_kiobuf: end %d\n", err);
-	return err;
 }
 
 /*
@@ -588,6 +598,9 @@
 		if (map) {
 			if (iobuf->locked)
 				UnlockPage(map);
+			/* FIXME: cache flush missing for rw==READ
+			 * FIXME: call the correct reference counting function
+			 */
 			page_cache_release(map);
 		}
 	}
@@ -1022,16 +1035,10 @@
 
 do_expand:
 	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-	if (limit != RLIM_INFINITY) {
-		if (inode->i_size >= limit) {
-			send_sig(SIGXFSZ, current, 0);
-			goto out;
-		}
-		if (offset > limit) {
-			send_sig(SIGXFSZ, current, 0);
-			offset = limit;
-		}
-	}
+	if (limit != RLIM_INFINITY && offset > limit)
+		goto out_sig;
+	if (offset > inode->i_sb->s_maxbytes)
+		goto out;
 	inode->i_size = offset;
 
 out_truncate:
@@ -1040,8 +1047,11 @@
 		inode->i_op->truncate(inode);
 		unlock_kernel();
 	}
-out:
 	return 0;
+out_sig:
+	send_sig(SIGXFSZ, current, 0);
+out:
+	return -EFBIG;
 }
 
 /* 
@@ -1223,7 +1233,7 @@
 		struct page * page = alloc_page(GFP_HIGHUSER);
 		if (!page)
 			return -1;
-		copy_highpage(page, new_page);
+		copy_user_highpage(page, new_page, address);
 		page_cache_release(new_page);
 		lru_cache_add(page);
 		new_page = page;
@@ -1412,23 +1422,19 @@
 	return pte_offset(pmd, address);
 }
 
-/*
- * Simplistic page force-in..
- */
 int make_pages_present(unsigned long addr, unsigned long end)
 {
-	int write;
-	struct mm_struct *mm = current->mm;
+	int ret, len, write;
 	struct vm_area_struct * vma;
 
-	vma = find_vma(mm, addr);
+	vma = find_vma(current->mm, addr);
 	write = (vma->vm_flags & VM_WRITE) != 0;
 	if (addr >= end)
 		BUG();
-	do {
-		if (handle_mm_fault(mm, vma, addr, write) < 0)
-			return -1;
-		addr += PAGE_SIZE;
-	} while (addr < end);
-	return 0;
+	if (end > vma->vm_end)
+		BUG();
+	len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE;
+	ret = get_user_pages(current, current->mm, addr,
+			len, write, 0, NULL, NULL);
+	return ret == len ? 0 : -1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/shmem.c linux/mm/shmem.c
--- linux-2.4.16/mm/shmem.c	Mon Nov 26 10:35:00 2001
+++ linux/mm/shmem.c	Thu Dec  6 16:13:26 2001
@@ -1193,7 +1193,7 @@
 	follow_link:	shmem_follow_link,
 };
 
-static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes)
+static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long * blocks, unsigned long *inodes)
 {
 	char *this_char, *value, *rest;
 
@@ -1205,7 +1205,7 @@
 			*value++ = 0;
 		} else {
 			printk(KERN_ERR 
-			    "shmem_parse_options: No value for option '%s'\n", 
+			    "tmpfs: No value for mount option '%s'\n", 
 			    this_char);
 			return 1;
 		}
@@ -1230,8 +1230,20 @@
 			*mode = simple_strtoul(value,&rest,8);
 			if (*rest)
 				goto bad_val;
+		} else if (!strcmp(this_char,"uid")) {
+			if (!uid)
+				continue;
+			*uid = simple_strtoul(value,&rest,0);
+			if (*rest)
+				goto bad_val;
+		} else if (!strcmp(this_char,"gid")) {
+			if (!gid)
+				continue;
+			*gid = simple_strtoul(value,&rest,0);
+			if (*rest)
+				goto bad_val;
 		} else {
-			printk(KERN_ERR "shmem_parse_options: Bad option %s\n",
+			printk(KERN_ERR "tmpfs: Bad mount option %s\n",
 			       this_char);
 			return 1;
 		}
@@ -1239,7 +1251,7 @@
 	return 0;
 
 bad_val:
-	printk(KERN_ERR "shmem_parse_options: Bad value '%s' for option '%s'\n", 
+	printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", 
 	       value, this_char);
 	return 1;
 
@@ -1251,7 +1263,7 @@
 	unsigned long max_blocks = sbinfo->max_blocks;
 	unsigned long max_inodes = sbinfo->max_inodes;
 
-	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
+	if (shmem_parse_options (data, NULL, NULL, NULL, &max_blocks, &max_inodes))
 		return -EINVAL;
 	return shmem_set_size(sbinfo, max_blocks, max_inodes);
 }
@@ -1268,6 +1280,8 @@
 	struct dentry * root;
 	unsigned long blocks, inodes;
 	int mode   = S_IRWXUGO | S_ISVTX;
+	uid_t uid = current->fsuid;
+	gid_t gid = current->fsgid;
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 	struct sysinfo si;
 
@@ -1279,10 +1293,8 @@
 	blocks = inodes = si.totalram / 2;
 
 #ifdef CONFIG_TMPFS
-	if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
-		printk(KERN_ERR "tmpfs invalid option\n");
+	if (shmem_parse_options (data, &mode, &uid, &gid, &blocks, &inodes))
 		return NULL;
-	}
 #endif
 
 	spin_lock_init (&sbinfo->stat_lock);
@@ -1299,6 +1311,8 @@
 	if (!inode)
 		return NULL;
 
+	inode->i_uid = uid;
+	inode->i_gid = gid;
 	root = d_alloc_root(inode);
 	if (!root) {
 		iput(inode);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/slab.c linux/mm/slab.c
--- linux-2.4.16/mm/slab.c	Mon Nov 26 10:35:00 2001
+++ linux/mm/slab.c	Thu Dec  6 15:44:37 2001
@@ -109,9 +109,11 @@
 #if DEBUG
 # define CREATE_MASK	(SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \
 			 SLAB_POISON | SLAB_HWCACHE_ALIGN | \
-			 SLAB_NO_REAP | SLAB_CACHE_DMA)
+			 SLAB_NO_REAP | SLAB_CACHE_DMA | \
+			 SLAB_MUST_HWCACHE_ALIGN)
 #else
-# define CREATE_MASK	(SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | SLAB_CACHE_DMA)
+# define CREATE_MASK	(SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | \
+			 SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN)
 #endif
 
 /*
@@ -649,7 +651,7 @@
 		flags &= ~SLAB_POISON;
 	}
 #if FORCED_DEBUG
-	if (size < (PAGE_SIZE>>3))
+	if ((size < (PAGE_SIZE>>3)) && !(flags & SLAB_MUST_HWCACHE_ALIGN))
 		/*
 		 * do not red zone large object, causes severe
 		 * fragmentation.
@@ -1280,10 +1282,9 @@
 })
 
 #ifdef CONFIG_SMP
-void* kmem_cache_alloc_batch(kmem_cache_t* cachep, int flags)
+void* kmem_cache_alloc_batch(kmem_cache_t* cachep, cpucache_t* cc, int flags)
 {
 	int batchcount = cachep->batchcount;
-	cpucache_t* cc = cc_data(cachep);
 
 	spin_lock(&cachep->spinlock);
 	while (batchcount--) {
@@ -1332,7 +1333,7 @@
 				objp = cc_entry(cc)[--cc->avail];
 			} else {
 				STATS_INC_ALLOCMISS(cachep);
-				objp = kmem_cache_alloc_batch(cachep,flags);
+				objp = kmem_cache_alloc_batch(cachep,cc,flags);
 				if (!objp)
 					goto alloc_new_slab_nolock;
 			}
@@ -1920,12 +1921,13 @@
 #endif
 #ifdef CONFIG_SMP
 		{
+			cpucache_t *cc = cc_data(cachep);
 			unsigned int batchcount = cachep->batchcount;
 			unsigned int limit;
 
-			if (cc_data(cachep))
-				limit = cc_data(cachep)->limit;
-			 else
+			if (cc)
+				limit = cc->limit;
+			else
 				limit = 0;
 			len += sprintf(page+len, " : %4u %4u",
 					limit, batchcount);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/mm/vmalloc.c linux/mm/vmalloc.c
--- linux-2.4.16/mm/vmalloc.c	Mon Nov 26 10:35:00 2001
+++ linux/mm/vmalloc.c	Thu Dec  6 20:33:49 2001
@@ -6,6 +6,7 @@
  *  SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000
  */
 
+#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/spinlock.h>
@@ -273,6 +274,43 @@
 			if (count == 0)
 				goto finished;
 			*buf = *addr;
+			buf++;
+			addr++;
+			count--;
+		} while (--n > 0);
+	}
+finished:
+	read_unlock(&vmlist_lock);
+	return buf - buf_start;
+}
+
+long vwrite(char *buf, char *addr, unsigned long count)
+{
+	struct vm_struct *tmp;
+	char *vaddr, *buf_start = buf;
+	unsigned long n;
+
+	/* Don't allow overflow */
+	if ((unsigned long) addr + count < count)
+		count = -(unsigned long) addr;
+
+	read_lock(&vmlist_lock);
+	for (tmp = vmlist; tmp; tmp = tmp->next) {
+		vaddr = (char *) tmp->addr;
+		if (addr >= vaddr + tmp->size - PAGE_SIZE)
+			continue;
+		while (addr < vaddr) {
+			if (count == 0)
+				goto finished;
+			buf++;
+			addr++;
+			count--;
+		}
+		n = vaddr + tmp->size - PAGE_SIZE - addr;
+		do {
+			if (count == 0)
+				goto finished;
+			*addr = *buf;
 			buf++;
 			addr++;
 			count--;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/8021q/vlan.c linux/net/8021q/vlan.c
--- linux-2.4.16/net/8021q/vlan.c	Mon Nov 26 10:35:01 2001
+++ linux/net/8021q/vlan.c	Thu Dec  6 15:47:36 2001
@@ -1,11 +1,10 @@
 /*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
+ * INET		802.1Q VLAN
  *		Ethernet-type device handling.
  *
- * Authors:	Ben Greear <greearb@candelatech.com>, <greearb@agcs.com>
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *              Please send support related email to: vlan@scry.wanfear.com
+ *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
  * 
  * Fixes:
  *              Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
@@ -42,7 +41,7 @@
 
 static char vlan_fullname[] = "802.1Q VLAN Support";
 static unsigned int vlan_version = 1;
-static unsigned int vlan_release = 5;
+static unsigned int vlan_release = 6;
 static char vlan_copyright[] = " Ben Greear <greearb@candelatech.com>";
 
 static int vlan_device_event(struct notifier_block *, unsigned long, void *);
@@ -106,6 +105,23 @@
 }
 
 /*
+ * Cleanup of groups before exit
+ */
+
+static void vlan_group_cleanup(void)
+{
+	struct vlan_group *grp = NULL;
+	struct vlan_group *nextgroup;
+
+	for (grp = p802_1Q_vlan_list; (grp != NULL);) {
+		nextgroup = grp->next;
+		kfree(grp);
+		grp = nextgroup;
+	}
+	p802_1Q_vlan_list = NULL;
+}
+
+/*
  *     Module 'remove' entry point.
  *     o delete /proc/net/router directory and static entries.
  */ 
@@ -116,7 +132,7 @@
 
 	dev_remove_pack(&vlan_packet_type);
 	vlan_proc_cleanup();
-
+	vlan_group_cleanup();
 	vlan_ioctl_hook = NULL;
 }
 
@@ -328,6 +344,7 @@
 	/* set up method calls */
 	new_dev->init = vlan_dev_init;
 	new_dev->destructor = vlan_dev_destruct;
+	new_dev->features |= NETIF_F_DYNALLOC ; 
 	    
 	/* new_dev->ifindex = 0;  it will be set when added to
 	 * the global list.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/8021q/vlan_dev.c linux/net/8021q/vlan_dev.c
--- linux-2.4.16/net/8021q/vlan_dev.c	Mon Nov 26 10:35:01 2001
+++ linux/net/8021q/vlan_dev.c	Thu Dec  6 15:47:36 2001
@@ -1,11 +1,10 @@
 /*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
+ * INET		802.1Q VLAN
  *		Ethernet-type device handling.
  *
- * Authors:	Ben Greear <greearb@candelatech.com>, <greearb@agcs.com>
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *              Please send support related email to: vlan@scry.wanfear.com
+ *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
  * 
  * Fixes:       Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com>
  *                - reset skb->pkt_type on incoming packets when MAC was changed
@@ -512,10 +511,6 @@
 			VLAN_FMEM_DBG("dev->priv free, addr: %p\n", dev->priv);
 			dev->priv = NULL;
 		}
-
-		kfree(dev);
-		VLAN_FMEM_DBG("net_device free, addr: %p\n", dev);
-		dev = NULL;
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/8021q/vlanproc.c linux/net/8021q/vlanproc.c
--- linux-2.4.16/net/8021q/vlanproc.c	Mon Nov 26 10:35:01 2001
+++ linux/net/8021q/vlanproc.c	Thu Dec  6 15:47:36 2001
@@ -116,7 +116,7 @@
  *	Clean up /proc/net/vlan entries
  */
 
-void __exit vlan_proc_cleanup(void)
+void vlan_proc_cleanup(void)
 {
 	if (proc_vlan_conf)
 		remove_proc_entry(name_conf, proc_vlan_dir);
@@ -462,7 +462,7 @@
 	return 0;
 }
 
-void __exit vlan_proc_cleanup(void)
+void vlan_proc_cleanup(void)
 {
 	return;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/Config.in linux/net/Config.in
--- linux-2.4.16/net/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/net/Config.in	Wed Dec  5 16:36:05 2001
@@ -7,11 +7,9 @@
 if [ "$CONFIG_PACKET" != "n" ]; then
    bool '  Packet socket: mmapped IO' CONFIG_PACKET_MMAP
 fi
-bool 'Kernel/User netlink socket' CONFIG_NETLINK
-if [ "$CONFIG_NETLINK" = "y" ]; then
-   bool '  Routing messages' CONFIG_RTNETLINK
-   tristate '  Netlink device emulation' CONFIG_NETLINK_DEV
-fi
+
+tristate 'Netlink device emulation' CONFIG_NETLINK_DEV
+
 bool 'Network packet filtering (replaces ipchains)' CONFIG_NETFILTER
 if [ "$CONFIG_NETFILTER" = "y" ]; then
    bool '  Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/Makefile linux/net/Makefile
--- linux-2.4.16/net/Makefile	Mon Nov 26 10:35:01 2001
+++ linux/net/Makefile	Wed Dec  5 16:36:05 2001
@@ -14,7 +14,7 @@
 subdir-m :=	ipv4 # hum?
 
 
-subdir-$(CONFIG_NET)		+= 802 sched
+subdir-$(CONFIG_NET)		+= 802 sched netlink
 subdir-$(CONFIG_INET)		+= ipv4
 subdir-$(CONFIG_NETFILTER)	+= ipv4/netfilter
 subdir-$(CONFIG_UNIX)		+= unix
@@ -27,7 +27,6 @@
 endif
 
 subdir-$(CONFIG_KHTTPD)		+= khttpd
-subdir-$(CONFIG_NETLINK)	+= netlink
 subdir-$(CONFIG_PACKET)		+= packet
 subdir-$(CONFIG_NET_SCHED)	+= sched
 subdir-$(CONFIG_BRIDGE)		+= bridge
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/README linux/net/README
--- linux-2.4.16/net/README	Mon Nov 26 10:35:01 2001
+++ linux/net/README	Thu Dec  6 15:47:36 2001
@@ -23,4 +23,4 @@
 unix			alan@lxorguk.ukuu.org.uk
 x25			g4klx@g4klx.demon.co.uk
 bluetooth		maxk@qualcomm.com
-
+8021q                   greearb@candelatech.com, vlan@scry.wanfear.com
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/bridge/br_if.c linux/net/bridge/br_if.c
--- linux-2.4.16/net/bridge/br_if.c	Mon Nov 26 10:35:01 2001
+++ linux/net/bridge/br_if.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_if.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ *	$Id: br_if.c,v 1.6 2001/11/24 17:51:03 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -261,8 +261,6 @@
 {
 	struct net_bridge *br;
 	int i;
-
-	i = 0;
 
 	br = bridge_list;
 	for (i=0;i<num;i++) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/core/datagram.c linux/net/core/datagram.c
--- linux-2.4.16/net/core/datagram.c	Mon Nov 26 10:35:01 2001
+++ linux/net/core/datagram.c	Wed Dec  5 16:36:06 2001
@@ -30,21 +30,18 @@
 #include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/in.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
 #include <linux/poll.h>
 #include <linux/highmem.h>
 
-#include <net/ip.h>
 #include <net/protocol.h>
-#include <net/route.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
+#include <net/checksum.h>
 
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/core/neighbour.c linux/net/core/neighbour.c
--- linux-2.4.16/net/core/neighbour.c	Mon Nov 26 10:35:01 2001
+++ linux/net/core/neighbour.c	Wed Dec  5 16:36:06 2001
@@ -1172,9 +1172,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
-
-
 int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct ndmsg *ndm = NLMSG_DATA(nlh);
@@ -1438,12 +1435,7 @@
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);
 }
 
-
-
-#endif
-
-
-#endif
+#endif /* CONFIG_ARPD */
 
 #ifdef CONFIG_SYSCTL
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- linux-2.4.16/net/core/rtnetlink.c	Mon Nov 26 10:35:01 2001
+++ linux/net/core/rtnetlink.c	Wed Dec  5 16:36:06 2001
@@ -77,15 +77,10 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 struct sock *rtnl;
 
 struct rtnetlink_link * rtnetlink_links[NPROTO];
 
-#define _S	1	/* superuser privileges required */
-#define _X	2	/* exclusive access to tables required */
-#define _G	4	/* GET request */
-
 static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
 {
 	NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -533,7 +528,3 @@
 	rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
 	rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
 }
-
-
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/core/scm.c linux/net/core/scm.c
--- linux-2.4.16/net/core/scm.c	Mon Nov 26 10:35:01 2001
+++ linux/net/core/scm.c	Wed Dec  5 16:36:06 2001
@@ -26,11 +26,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#include <linux/inet.h>
-#include <net/ip.h>
 #include <net/protocol.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/scm.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/core/skbuff.c linux/net/core/skbuff.c
--- linux-2.4.16/net/core/skbuff.c	Mon Nov 26 10:35:01 2001
+++ linux/net/core/skbuff.c	Wed Dec  5 16:36:06 2001
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.89 2001/08/06 13:25:02 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -49,15 +49,14 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/cache.h>
+#include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
 
-#include <net/ip.h>
 #include <net/protocol.h>
 #include <net/dst.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <net/sock.h>
+#include <net/checksum.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/core/sock.c linux/net/core/sock.c
--- linux-2.4.16/net/core/sock.c	Mon Nov 26 10:35:01 2001
+++ linux/net/core/sock.c	Wed Dec  5 16:36:06 2001
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.112 2001/07/27 09:54:48 davem Exp $
+ * Version:	$Id: sock.c,v 1.116 2001/11/08 04:20:06 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -113,24 +113,20 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#include <linux/inet.h>
 #include <linux/netdevice.h>
-#include <net/ip.h>
 #include <net/protocol.h>
-#include <net/arp.h>
-#include <net/route.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/raw.h>
-#include <net/icmp.h>
 #include <linux/ipsec.h>
 
 #ifdef CONFIG_FILTER
 #include <linux/filter.h>
 #endif
 
+#ifdef CONFIG_INET
+#include <net/tcp.h>
+#endif
+
 /* Run time adjustable parameters. */
 __u32 sysctl_wmem_max = SK_WMEM_MAX;
 __u32 sysctl_rmem_max = SK_RMEM_MAX;
@@ -759,48 +755,62 @@
  *	Generic send/receive buffer handlers
  */
 
-struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
-			int noblock, int *errcode)
+struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
+				     unsigned long data_len, int noblock, int *errcode)
 {
-	int err;
 	struct sk_buff *skb;
 	long timeo;
+	int err;
 
 	timeo = sock_sndtimeo(sk, noblock);
-
 	while (1) {
-		unsigned long try_size = size;
-
 		err = sock_error(sk);
 		if (err != 0)
 			goto failure;
 
-		/*
-		 *	We should send SIGPIPE in these cases according to
-		 *	1003.1g draft 6.4. If we (the user) did a shutdown()
-		 *	call however we should not. 
-		 *
-		 *	Note: This routine isnt just used for datagrams and
-		 *	anyway some datagram protocols have a notion of
-		 *	close down.
-		 */
-
 		err = -EPIPE;
-		if (sk->shutdown&SEND_SHUTDOWN)
+		if (sk->shutdown & SEND_SHUTDOWN)
 			goto failure;
 
 		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
-			skb = alloc_skb(try_size, sk->allocation);
-			if (skb)
+			skb = alloc_skb(header_len, sk->allocation);
+			if (skb) {
+				int npages;
+				int i;
+
+				/* No pages, we're done... */
+				if (!data_len)
+					break;
+
+				npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+				skb->truesize += data_len;
+				skb_shinfo(skb)->nr_frags = npages;
+				for (i = 0; i < npages; i++) {
+					struct page *page;
+					skb_frag_t *frag;
+
+					page = alloc_pages(sk->allocation, 0);
+					if (!page) {
+						err = -ENOBUFS;
+						kfree_skb(skb);
+						goto failure;
+					}
+
+					frag = &skb_shinfo(skb)->frags[i];
+					frag->page = page;
+					frag->page_offset = 0;
+					frag->size = (data_len >= PAGE_SIZE ?
+						      PAGE_SIZE :
+						      data_len);
+					data_len -= PAGE_SIZE;
+				}
+
+				/* Full success... */
 				break;
+			}
 			err = -ENOBUFS;
 			goto failure;
 		}
-
-		/*
-		 *	This means we have too many buffers for this socket already.
-		 */
-
 		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 		set_bit(SOCK_NOSPACE, &sk->socket->flags);
 		err = -EAGAIN;
@@ -819,6 +829,12 @@
 failure:
 	*errcode = err;
 	return NULL;
+}
+
+struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
+				    int noblock, int *errcode)
+{
+	return sock_alloc_send_pskb(sk, size, 0, noblock, errcode);
 }
 
 void __lock_sock(struct sock *sk)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/README linux/net/decnet/README
--- linux-2.4.16/net/decnet/README	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/README	Thu Dec  6 15:47:36 2001
@@ -3,6 +3,6 @@
 
 The documentation for this kernel subsystem is available in the
 Documentation/networking subdirctory of this distribution and also
-on line at http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html.
+on line at http://www.chygwyn.com/DECnet/
 
 Steve Whitehouse <SteveW@ACM.org>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- linux-2.4.16/net/decnet/af_decnet.c	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/af_decnet.c	Thu Dec  6 15:47:36 2001
@@ -36,6 +36,7 @@
  *        Steve Whitehouse: Removed unused code. Fix to use sk->allocation
  *                          when required.
  *       Patrick Caulfield: /proc/net/decnet now has object name/number
+ *        Steve Whitehouse: Fixed local port allocation, hashed sk list
  */
 
 
@@ -139,9 +140,13 @@
 dn_address decnet_address = 0;
 unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };
 
+#define DN_SK_HASH_SHIFT 8
+#define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
+#define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
+
 static struct proto_ops dn_proto_ops;
 rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
-static struct sock *dn_sklist;
+static struct sock *dn_sk_hash[DN_SK_HASH_SIZE];
 static struct sock *dn_wild_sk;
 
 static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags);
@@ -154,18 +159,38 @@
 	if (scp->addr.sdn_flags & SDF_WILD)
 		return dn_wild_sk ? NULL : &dn_wild_sk;
 
-	return &dn_sklist;
+	return &dn_sk_hash[scp->addrloc & DN_SK_HASH_MASK];
+}
+
+/* 
+ * Valid ports are those greater than zero and not already in use.
+ */
+static int check_port(unsigned short port)
+{
+	struct sock *sk = dn_sk_hash[port & DN_SK_HASH_MASK];
+	if (port == 0)
+		return -1;
+	while(sk) {
+		struct dn_scp *scp = DN_SK(sk);
+		if (scp->addrloc == port)
+			return -1;
+		sk = sk->next;
+	}
+	return 0;
 }
 
 static unsigned short port_alloc(struct sock *sk)
 {
 	struct dn_scp *scp = DN_SK(sk);
 static unsigned short port = 0x2000;
+	unsigned short i_port = port;
 
-	if (port == 0)
-		port++;
+	while(check_port(++port) != 0) {
+		if (port == i_port)
+			return 0;
+	}
 
-	scp->addrloc = port++;
+	scp->addrloc = port;
 
 	return 1;
 }
@@ -238,6 +263,48 @@
 	sk->pprev = NULL;
 }
 
+struct sock **listen_hash(struct sockaddr_dn *addr)
+{
+	int i;
+	unsigned hash = addr->sdn_objnum;
+
+	if (hash == 0) {
+		hash = addr->sdn_objnamel;
+		for(i = 0; i < addr->sdn_objnamel; i++) {
+			hash ^= addr->sdn_objname[i];
+			hash ^= (hash << 3);
+		}
+	}
+
+	return &dn_sk_hash[hash & DN_SK_HASH_MASK];
+}
+
+/*
+ * Called to transform a socket from bound (i.e. with a local address)
+ * into a listening socket (doesn't need a local port number) and rehashes
+ * based upon the object name/number.
+ */
+static void dn_rehash_sock(struct sock *sk)
+{
+	struct sock **skp = sk->pprev;
+	struct dn_scp *scp = DN_SK(sk);
+
+	if (scp->addr.sdn_flags & SDF_WILD)
+		return;
+
+	write_lock_bh(&dn_hash_lock);
+	while(*skp != sk)
+		skp = &((*skp)->next);
+	*skp = sk->next;
+
+	DN_SK(sk)->addrloc = 0;
+	skp = listen_hash(&DN_SK(sk)->addr);
+
+	sk->next = *skp;
+	sk->pprev = skp;
+	*skp = sk;
+	write_unlock_bh(&dn_hash_lock);
+}
 
 int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned char type)
 {
@@ -328,10 +395,11 @@
 
 struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr)
 {
+	struct sock **skp = listen_hash(addr);
 	struct sock *sk;
 
 	read_lock(&dn_hash_lock);
-	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
+	for(sk = *skp; sk != NULL; sk = sk->next) {
 		struct dn_scp *scp = DN_SK(sk);
 		if (sk->state != TCP_LISTEN)
 			continue;
@@ -365,7 +433,8 @@
 	struct dn_scp *scp;
 
 	read_lock(&dn_hash_lock);
-	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
+	sk = dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK];
+	for (; sk != NULL; sk = sk->next) {
 		scp = DN_SK(sk);
 		if (cb->src != dn_saddr2dn(&scp->peer))
 			continue;
@@ -1045,6 +1114,9 @@
 		sizeof(struct optdata_dn));
 
 	lock_sock(newsk);
+	/*
+	 * FIXME: This can fail if we've run out of local ports....
+	 */
 	dn_hash_sock(newsk);
 
 	dn_send_conn_ack(newsk);
@@ -1200,6 +1272,7 @@
 	sk->ack_backlog     = 0;
 	sk->state           = TCP_LISTEN;
 	err                 = 0;
+	dn_rehash_sock(sk);
 
 out:
 	release_sock(sk);
@@ -2063,44 +2136,47 @@
 	char buf2[DN_ASCBUF_LEN];
 	char local_object[DN_MAXOBJL+3];
 	char remote_object[DN_MAXOBJL+3];
+	int i;
 
 	len += sprintf(buffer + len, "Local                                              Remote\n");
 
 	read_lock(&dn_hash_lock);
-	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
-		scp = DN_SK(sk);
-
-		dn_printable_object(&scp->addr, local_object);
-		dn_printable_object(&scp->peer, remote_object);
-
-		len += sprintf(buffer + len,
-				"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
-				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
-				scp->addrloc,
-				scp->numdat,
-				scp->numoth,
-				scp->ackxmt_dat,
-				scp->ackxmt_oth,
-				scp->flowloc_sw,
-				local_object,
-				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
-				scp->addrrem,
-				scp->numdat_rcv,
-				scp->numoth_rcv,
-				scp->ackrcv_dat,
-				scp->ackrcv_oth,
-				scp->flowrem_sw,
-				remote_object,
-				dn_state2asc(scp->state),
-				((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
-
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
+	for(i = 0; i < DN_SK_HASH_SIZE; i++) {
+		for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {
+			scp = DN_SK(sk);
+
+			dn_printable_object(&scp->addr, local_object);
+			dn_printable_object(&scp->peer, remote_object);
+
+			len += sprintf(buffer + len,
+					"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
+					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+					scp->addrloc,
+					scp->numdat,
+					scp->numoth,
+					scp->ackxmt_dat,
+					scp->ackxmt_oth,
+					scp->flowloc_sw,
+					local_object,
+					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+					scp->addrrem,
+					scp->numdat_rcv,
+					scp->numoth_rcv,
+					scp->ackrcv_dat,
+					scp->ackrcv_oth,
+					scp->flowrem_sw,
+					remote_object,
+					dn_state2asc(scp->state),
+					((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
+
+			pos = begin + len;
+			if (pos < offset) {
+				len = 0;
+				begin = pos;
+			}
+			if (pos > (offset + length))
+				break;
 		}
-		if (pos > (offset + length))
-			break;
 	}
 	read_unlock(&dn_hash_lock);
 
@@ -2158,7 +2234,7 @@
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 #endif
 
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.9s (C) 1995-2001 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- linux-2.4.16/net/decnet/dn_dev.c	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/dn_dev.c	Wed Dec  5 16:36:06 2001
@@ -56,9 +56,7 @@
 
 static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
 static void dn_dev_delete(struct net_device *dev);
-#ifdef CONFIG_RTNETLINK
 static void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
-#endif
 
 static int dn_eth_up(struct net_device *);
 static void dn_send_brd_hello(struct net_device *dev);
@@ -369,9 +367,7 @@
 
 	*ifap = ifa1->ifa_next;
 
-#ifdef CONFIG_RTNETLINK
 	rtmsg_ifa(RTM_DELADDR, ifa1);
-#endif /* CONFIG_RTNETLINK */
 
 	if (destroy) {
 		dn_dev_free_ifa(ifa1);
@@ -390,9 +386,7 @@
 	ifa->ifa_next = dn_db->ifa_list;
 	dn_db->ifa_list = ifa;
 
-#ifdef CONFIG_RTNETLINK
 	rtmsg_ifa(RTM_NEWADDR, ifa);
-#endif /* CONFIG_RTNETLINK */
 
 	return 0;
 }
@@ -501,7 +495,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static struct dn_dev *dn_dev_by_index(int ifindex)
 {
 	struct net_device *dev;
@@ -658,8 +651,6 @@
 	return skb->len;
 }
 
-#endif /* CONFIG_RTNETLINK */
-
 static void dn_send_endnode_hello(struct net_device *dev)
 {
         struct endnode_hello_message *msg;
@@ -1172,7 +1163,6 @@
 
 #endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_RTNETLINK
 static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
 {
 	{ NULL,			NULL,			},
@@ -1213,7 +1203,6 @@
 	{ NULL,			NULL,			}
 #endif
 };
-#endif /* CONFIG_RTNETLINK */
 
 void __init dn_dev_init(void)
 {
@@ -1223,9 +1212,7 @@
 	register_gifconf(PF_DECnet, dnet_gifconf);
 #endif /* CONFIG_DECNET_SIOCGIFCONF */
 
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
-#endif /* CONFIG_RTNETLINK */
 
 #ifdef CONFIG_PROC_FS
 	proc_net_create("decnet_dev", 0, decnet_dev_get_info);
@@ -1242,9 +1229,7 @@
 
 void __exit dn_dev_cleanup(void)
 {
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_DECnet] = NULL;
-#endif /* CONFIG_RTNETLINK */
 
 #ifdef CONFIG_DECNET_SIOCGIFCONF
 	unregister_gifconf(PF_DECnet);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- linux-2.4.16/net/decnet/dn_fib.c	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/dn_fib.c	Wed Dec  5 16:36:06 2001
@@ -50,9 +50,7 @@
 
 #define endfor_nexthops(fi) }
 
-#ifdef CONFIG_RTNETLINK
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
 
 
 static struct dn_fib_info *dn_fib_info_list;
@@ -415,8 +413,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
 	int i;
@@ -497,7 +493,6 @@
 
 	return skb->len;
 }
-#endif /* CONFIG_RTNETLINK */
 
 int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- linux-2.4.16/net/decnet/dn_route.c	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/dn_route.c	Wed Dec  5 16:36:06 2001
@@ -1020,7 +1020,6 @@
 	return dn_route_input_slow(skb);
 }
 
-#ifdef CONFIG_RTNETLINK
 static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait)
 {
 	struct dn_route *rt = (struct dn_route *)skb->dst;
@@ -1181,7 +1180,6 @@
 	cb->args[1] = idx;
 	return skb->len;
 }
-#endif /* CONFIG_RTNETLINK */
 
 #ifdef CONFIG_PROC_FS
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/dn_rules.c linux/net/decnet/dn_rules.c
--- linux-2.4.16/net/decnet/dn_rules.c	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/dn_rules.c	Wed Dec  5 16:36:06 2001
@@ -299,8 +299,6 @@
 	notifier_call:		dn_fib_rules_event,
 };
 
-#ifdef CONFIG_RTNETLINK
-
 static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb)
 {
 	struct rtmsg *rtm;
@@ -359,8 +357,6 @@
 
 	return skb->len;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 void __init dn_fib_rules_init(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/dn_table.c linux/net/decnet/dn_table.c
--- linux-2.4.16/net/decnet/dn_table.c	Mon Nov 26 10:35:01 2001
+++ linux/net/decnet/dn_table.c	Wed Dec  5 16:36:06 2001
@@ -267,7 +267,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
                         u8 tb_id, u8 type, u8 scope, void *dst, int dst_len,
                         struct dn_fib_info *fi)
@@ -435,12 +434,6 @@
         return skb->len;
 }
 
-#else /* no CONFIG_RTNETLINK */
-
-#define dn_rtmsg_fib(event,f,z,tb_id,nlh,req)
-
-#endif /* CONFIG_RTNETLINK */
-
 static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
 {
 	struct dn_hash *table = (struct dn_hash *)tb->data;
@@ -860,9 +853,7 @@
 #ifdef CONFIG_PROC_FS
 	t->get_info = dn_fib_table_get_info;
 #endif
-#ifdef CONFIG_RTNETLINK
         t->dump = dn_fib_table_dump;
-#endif
         dn_fib_tables[n] = t;
 
         return t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/Config.in linux/net/ipv4/Config.in
--- linux-2.4.16/net/ipv4/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/Config.in	Wed Dec  5 16:36:06 2001
@@ -4,8 +4,6 @@
 bool '  IP: multicasting' CONFIG_IP_MULTICAST
 bool '  IP: advanced router' CONFIG_IP_ADVANCED_ROUTER
 if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then
-   define_bool CONFIG_RTNETLINK y	
-   define_bool CONFIG_NETLINK y
    bool '    IP: policy routing' CONFIG_IP_MULTIPLE_TABLES
    if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
       if [ "$CONFIG_NETFILTER" = "y" ]; then
@@ -39,9 +37,7 @@
    fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   if [ "$CONFIG_RTNETLINK" = "y" ]; then
-      bool '  IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
-   fi
+   bool '  IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
 fi
 bool '  IP: TCP Explicit Congestion Notification support' CONFIG_INET_ECN
 bool '  IP: TCP syncookie support (disabled per default)' CONFIG_SYN_COOKIES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/Makefile linux/net/ipv4/Makefile
--- linux-2.4.16/net/ipv4/Makefile	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/Makefile	Wed Dec  5 16:36:06 2001
@@ -15,7 +15,7 @@
 	     ip_input.o ip_fragment.o ip_forward.o ip_options.o \
 	     ip_output.o ip_sockglue.o \
 	     tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \
-	     raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
+	     tcp_diag.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
 	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o
 
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux-2.4.16/net/ipv4/af_inet.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/af_inet.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.135 2001/10/27 03:27:13 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.136 2001/11/06 22:21:08 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- linux-2.4.16/net/ipv4/devinet.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/devinet.c	Wed Dec  5 16:36:06 2001
@@ -1,7 +1,7 @@
 /*
  *	NET3	IP device support routines.
  *
- *	Version: $Id: devinet.c,v 1.43 2001/09/26 22:52:58 davem Exp $
+ *	Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -63,11 +63,7 @@
 struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, };
 static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, };
 
-#ifdef CONFIG_RTNETLINK
 static void rtmsg_ifa(int event, struct in_ifaddr *);
-#else
-#define rtmsg_ifa(a,b)	do { } while(0)
-#endif
 
 static struct notifier_block *inetaddr_chain;
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy);
@@ -359,8 +355,6 @@
 	return NULL;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 int
 inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
@@ -437,8 +431,6 @@
 	return inet_insert_ifa(ifa);
 }
 
-#endif
-
 /* 
  *	Determine a default network mask, based on the IP address. 
  */
@@ -859,8 +851,6 @@
 	notifier_call:	inetdev_event,
 };
 
-#ifdef CONFIG_RTNETLINK
-
 static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
 			    u32 pid, u32 seq, int event)
 {
@@ -994,8 +984,6 @@
 #endif
 };
 
-#endif /* CONFIG_RTNETLINK */
-
 
 #ifdef CONFIG_SYSCTL
 
@@ -1150,9 +1138,7 @@
 {
 	register_gifconf(PF_INET, inet_gifconf);
 	register_netdevice_notifier(&ip_netdev_notifier);
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_INET] = inet_rtnetlink_table;
-#endif
 #ifdef CONFIG_SYSCTL
 	devinet_sysctl.sysctl_header =
 		register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- linux-2.4.16/net/ipv4/fib_frontend.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/fib_frontend.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:	$Id: fib_frontend.c,v 1.25 2001/05/29 22:16:25 davem Exp $
+ * Version:	$Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -332,8 +332,6 @@
 
 #endif
 
-#ifdef CONFIG_RTNETLINK
-
 static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
 	int i;
@@ -408,8 +406,6 @@
 
 	return skb->len;
 }
-
-#endif
 
 /* Prepare and feed intra-kernel routing request.
    Really, it should be netlink message, but :-( netlink
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
--- linux-2.4.16/net/ipv4/fib_hash.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/fib_hash.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 FIB: lookup engine and maintenance routines.
  *
- * Version:	$Id: fib_hash.c,v 1.12 1999/08/31 07:03:27 davem Exp $
+ * Version:	$Id: fib_hash.c,v 1.13 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -425,14 +425,9 @@
 #endif
 
 
-#ifdef CONFIG_RTNETLINK
 static void rtmsg_fib(int, struct fib_node*, int, int,
 		      struct nlmsghdr *n,
 		      struct netlink_skb_parms *);
-#else
-#define rtmsg_fib(a, b, c, d, e, f)
-#endif
-
 
 static int
 fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
@@ -796,9 +791,7 @@
 #endif
 
 
-#ifdef CONFIG_RTNETLINK
-
-extern __inline__ int
+static __inline__ int
 fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
 		     struct fib_table *tb,
 		     struct fn_zone *fz,
@@ -823,7 +816,7 @@
 	return skb->len;
 }
 
-extern __inline__ int
+static __inline__ int
 fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
 		   struct fib_table *tb,
 		   struct fn_zone *fz)
@@ -894,8 +887,6 @@
 		netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
 }
 
-#endif /* CONFIG_RTNETLINK */
-
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 struct fib_table * fib_hash_init(int id)
 #else
@@ -920,9 +911,7 @@
 	tb->tb_delete = fn_hash_delete;
 	tb->tb_flush = fn_hash_flush;
 	tb->tb_select_default = fn_hash_select_default;
-#ifdef CONFIG_RTNETLINK
 	tb->tb_dump = fn_hash_dump;
-#endif
 #ifdef CONFIG_PROC_FS
 	tb->tb_get_info = fn_hash_get_info;
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
--- linux-2.4.16/net/ipv4/fib_rules.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/fib_rules.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: policy rules.
  *
- * Version:	$Id: fib_rules.c,v 1.16 2001/04/30 04:39:14 davem Exp $
+ * Version:	$Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -395,9 +395,7 @@
 	notifier_call:	fib_rules_event,
 };
 
-#ifdef CONFIG_RTNETLINK
-
-extern __inline__ int inet_fill_rule(struct sk_buff *skb,
+static __inline__ int inet_fill_rule(struct sk_buff *skb,
 				     struct fib_rule *r,
 				     struct netlink_callback *cb)
 {
@@ -462,8 +460,6 @@
 
 	return skb->len;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 void __init fib_rules_init(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
--- linux-2.4.16/net/ipv4/fib_semantics.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/fib_semantics.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: semantics.
  *
- * Version:	$Id: fib_semantics.c,v 1.17 2000/08/19 23:22:56 davem Exp $
+ * Version:	$Id: fib_semantics.c,v 1.18 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -626,8 +626,6 @@
 	return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
 }
 
-#ifdef CONFIG_RTNETLINK
-
 int
 fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 	      u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos,
@@ -697,8 +695,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 #ifndef CONFIG_IP_NOSIOCRT
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- linux-2.4.16/net/ipv4/ipconfig.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/ipconfig.c	Wed Dec  5 16:36:06 2001
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.42 2001/11/10 07:23:12 davem Exp $
+ *  $Id: ipconfig.c,v 1.43 2001/11/21 20:27:34 davem Exp $
  *
  *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
  *  user-supplied information to configure own IP address and routes.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- linux-2.4.16/net/ipv4/ipmr.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/ipmr.c	Wed Dec  5 16:36:06 2001
@@ -9,7 +9,7 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
- *	Version: $Id: ipmr.c,v 1.64 2001/09/18 22:29:09 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $
  *
  *	Fixes:
  *	Michael Chastain	:	Incorrect size of copying.
@@ -294,7 +294,6 @@
 	atomic_dec(&cache_resolve_queue_len);
 
 	while((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) {
-#ifdef CONFIG_RTNETLINK
 		if (skb->nh.iph->version == 0) {
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 			nlh->nlmsg_type = NLMSG_ERROR;
@@ -303,7 +302,6 @@
 			((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
 			netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
 		} else
-#endif
 			kfree_skb(skb);
 	}
 
@@ -501,7 +499,6 @@
 	 */
 
 	while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
-#ifdef CONFIG_RTNETLINK
 		if (skb->nh.iph->version == 0) {
 			int err;
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
@@ -516,7 +513,6 @@
 			}
 			err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
 		} else
-#endif
 			ip_mr_forward(skb, c, 0);
 	}
 }
@@ -1522,8 +1518,6 @@
 }
 #endif
 
-#ifdef CONFIG_RTNETLINK
-
 static int
 ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
 {
@@ -1598,7 +1592,6 @@
 	read_unlock(&mrt_lock);
 	return err;
 }
-#endif
 
 #ifdef CONFIG_PROC_FS	
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- linux-2.4.16/net/ipv4/netfilter/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/Config.in	Wed Dec  5 16:36:06 2001
@@ -10,7 +10,7 @@
   dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
 fi
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP_NF_QUEUE
 fi
 tristate 'IP tables support (required for filtering/masq/NAT)' CONFIG_IP_NF_IPTABLES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ip_conntrack_irc.c linux/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.4.16/net/ipv4/netfilter/ip_conntrack_irc.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ip_conntrack_irc.c	Mon Dec 10 19:09:19 2001
@@ -1,8 +1,8 @@
-/* IRC extension for IP connection tracking, Version 1.19
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+/* IRC extension for IP connection tracking, Version 1.20
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  * based on RR's ip_conntrack_ftp.c	
  *
- * ip_conntrack_irc.c,v 1.19 2001/10/25 14:34:21 laforge Exp
+ * ip_conntrack_irc.c,v 1.20 2001/12/06 07:42:10 laforge Exp
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -10,7 +10,7 @@
  *      2 of the License, or (at your option) any later version.
  **
  *	Module load syntax:
- * 	insmod ip_nat_irc.o ports=port1,port2,...port<MAX_PORTS>
+ * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
  *	
  * 	please give the ports of all IRC servers You wish to connect to.
  *	If You don't specify ports, the default will be port 6667
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c
--- linux-2.4.16/net/ipv4/netfilter/ip_fw_compat.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat.c	Mon Dec 10 19:09:19 2001
@@ -84,6 +84,16 @@
 	if ((*pskb)->ip_summed == CHECKSUM_HW)
 		(*pskb)->ip_summed = CHECKSUM_NONE;
 
+	/* Firewall rules can alter TOS: raw socket (tcpdump) may have
+           clone of incoming skb: don't disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
 	switch (hooknum) {
 	case NF_IP_PRE_ROUTING:
 		if (fwops->fw_acct_in)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
--- linux-2.4.16/net/ipv4/netfilter/ip_fw_compat_redir.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Thu Dec  6 15:47:36 2001
@@ -206,6 +206,8 @@
 			}
 			list_prepend(&redirs, redir);
 			init_timer(&redir->destroyme);
+			redir->destroyme.expires = jiffies + 75*HZ;
+			add_timer(&redir->destroyme);
 		}
 		/* In case mangling has changed, rewrite this part. */
 		redir->core = ((struct redir_core)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.16/net/ipv4/netfilter/ip_nat_core.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_core.c	Mon Dec 10 19:09:19 2001
@@ -734,6 +734,18 @@
 	   synchronize_bh()) can vanish. */
 	READ_LOCK(&ip_nat_lock);
 	for (i = 0; i < info->num_manips; i++) {
+		/* raw socket (tcpdump) may have clone of incoming
+                   skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb) {
+				READ_UNLOCK(&ip_nat_lock);
+				return NF_DROP;
+			}
+			kfree_skb(*pskb);
+			*pskb = nskb;
+		}
+
 		if (info->manips[i].direction == dir
 		    && info->manips[i].hooknum == hooknum) {
 			DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ip_nat_helper.c linux/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.16/net/ipv4/netfilter/ip_nat_helper.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_helper.c	Mon Dec 10 19:09:19 2001
@@ -143,6 +143,23 @@
 		}
 	}
 
+	/* 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;
 	tcph = (void *)iph + iph->ihl*4;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ip_nat_irc.c linux/net/ipv4/netfilter/ip_nat_irc.c
--- linux-2.4.16/net/ipv4/netfilter/ip_nat_irc.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_irc.c	Mon Dec 10 19:09:19 2001
@@ -1,8 +1,8 @@
 /* IRC extension for TCP NAT alteration.
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  * based on a copy of RR's ip_nat_ftp.c
  *
- * ip_nat_irc.c,v 1.15 2001/10/22 10:43:53 laforge Exp
+ * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -81,7 +81,7 @@
 	}
 
 	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-	newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
 	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ipt_MIRROR.c linux/net/ipv4/netfilter/ipt_MIRROR.c
--- linux-2.4.16/net/ipv4/netfilter/ipt_MIRROR.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ipt_MIRROR.c	Mon Dec 10 19:09:19 2001
@@ -6,6 +6,10 @@
 
   Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
 
+  Changes:
+	25 Aug 2001 Harald Welte <laforge@gnumonks.org>
+		- decrement and check TTL if not called from FORWARD hook
+
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
@@ -24,6 +28,7 @@
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <net/ip.h>
+#include <net/icmp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netdevice.h>
 #include <linux/route.h>
@@ -100,15 +105,31 @@
 				      const void *targinfo,
 				      void *userinfo)
 {
-	if ((*pskb)->dst != NULL) {
-		if (route_mirror(*pskb)) {
-			ip_rewrite(*pskb);
-			/* Don't let conntrack code see this packet:
-                           it will think we are starting a new
-                           connection! --RR */
-			ip_direct_send(*pskb);
-			return NF_STOLEN;
+	if (((*pskb)->dst != NULL) &&
+	    route_mirror(*pskb)) {
+
+		ip_rewrite(*pskb);
+
+		/* If we are not at FORWARD hook (INPUT/PREROUTING),
+		 * the TTL isn't decreased by the IP stack */
+		if (hooknum != NF_IP_FORWARD) {
+			struct iphdr *iph = (*pskb)->nh.iph;
+			if (iph->ttl <= 1) {
+				/* this will traverse normal stack, and 
+				 * thus call conntrack on the icmp packet */
+				icmp_send(*pskb, ICMP_TIME_EXCEEDED, 
+					  ICMP_EXC_TTL, 0);
+				return NF_DROP;
+			}
+			ip_decrease_ttl(iph);
 		}
+
+		/* Don't let conntrack code see this packet:
+                   it will think we are starting a new
+                   connection! --RR */
+		ip_direct_send(*pskb);
+
+		return NF_STOLEN;
 	}
 	return NF_DROP;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ipt_TCPMSS.c linux/net/ipv4/netfilter/ipt_TCPMSS.c
--- linux-2.4.16/net/ipv4/netfilter/ipt_TCPMSS.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ipt_TCPMSS.c	Mon Dec 10 19:09:19 2001
@@ -44,11 +44,22 @@
 {
 	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
 	struct tcphdr *tcph;
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph;
 	u_int16_t tcplen, newtotlen, oldval, newmss;
 	unsigned int i;
 	u_int8_t *opt;
 
+	/* raw socket (tcpdump) may have clone of incoming skb: don't
+	   disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
+	iph = (*pskb)->nh.iph;
 	tcplen = (*pskb)->len - iph->ihl*4;
 
 	tcph = (void *)iph + iph->ihl*4;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ipt_TOS.c linux/net/ipv4/netfilter/ipt_TOS.c
--- linux-2.4.16/net/ipv4/netfilter/ipt_TOS.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ipt_TOS.c	Mon Dec 10 19:09:19 2001
@@ -21,6 +21,17 @@
 	if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
 		u_int16_t diffs[2];
 
+		/* raw socket (tcpdump) may have clone of incoming
+                   skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			*pskb = nskb;
+			kfree_skb(*pskb);
+			iph = (*pskb)->nh.iph;
+		}
+
 		diffs[0] = htons(iph->tos) ^ 0xFFFF;
 		iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
 		diffs[1] = htons(iph->tos);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.4.16/net/ipv4/netfilter/ipt_unclean.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/netfilter/ipt_unclean.c	Thu Dec  6 15:47:36 2001
@@ -257,6 +257,8 @@
 #define	TH_PUSH	0x08
 #define	TH_ACK	0x10
 #define	TH_URG	0x20
+#define	TH_ECE	0x40
+#define	TH_CWR	0x80
 
 /* TCP-specific checks. */
 static int
@@ -328,9 +330,10 @@
 	}
 
 	/* CHECK: TCP flags. */
-	tcpflags = ((u_int8_t *)tcph)[13];
+	tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
 	if (tcpflags != TH_SYN
 	    && tcpflags != (TH_SYN|TH_ACK)
+		&& tcpflags != TH_RST
 	    && tcpflags != (TH_RST|TH_ACK)
 	    && tcpflags != (TH_RST|TH_ACK|TH_PUSH)
 	    && tcpflags != (TH_FIN|TH_ACK)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/route.c linux/net/ipv4/route.c
--- linux-2.4.16/net/ipv4/route.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/route.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.101 2001/10/20 00:00:11 davem Exp $
+ * Version:	$Id: route.c,v 1.102 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2013,7 +2013,6 @@
 	return ip_route_output_slow(rp, key);
 }	
 
-#ifdef CONFIG_RTNETLINK
 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 			int nowait)
 {
@@ -2218,8 +2217,6 @@
 	cb->args[1] = idx;
 	return skb->len;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 void ip_rt_multicast_event(struct in_device *in_dev)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux-2.4.16/net/ipv4/tcp.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/tcp.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.214 2001/10/20 00:00:11 davem Exp $
+ * Version:	$Id: tcp.c,v 1.215 2001/10/31 08:17:58 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2442,6 +2442,7 @@
 
 
 extern void __skb_cb_too_small_for_tcp(int, int);
+extern void tcpdiag_init(void);
 
 void __init tcp_init(void)
 {
@@ -2553,4 +2554,6 @@
 
 	printk("TCP: Hash tables configured (established %d bind %d)\n",
 	       tcp_ehash_size<<1, tcp_bhash_size);
+
+	tcpdiag_init();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/tcp_diag.c linux/net/ipv4/tcp_diag.c
--- linux-2.4.16/net/ipv4/tcp_diag.c	Thu Jan  1 00:00:00 1970
+++ linux/net/ipv4/tcp_diag.c	Thu Dec  6 17:41:02 2001
@@ -0,0 +1,609 @@
+/*
+ * tcp_diag.c	Module for monitoring TCP sockets.
+ *
+ * Version:	$Id: tcp_diag.c,v 1.2 2001/11/05 09:42:22 davem Exp $
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the 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/types.h>
+#include <linux/fcntl.h>
+#include <linux/random.h>
+#include <linux/cache.h>
+#include <linux/init.h>
+
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <net/inet_common.h>
+
+#include <linux/inet.h>
+#include <linux/stddef.h>
+
+#include <linux/tcp_diag.h>
+
+static struct sock *tcpnl;
+
+
+#define TCPDIAG_PUT(skb, attrtype, attrlen) \
+({ int rtalen = RTA_LENGTH(attrlen);        \
+   struct rtattr *rta;                      \
+   if (skb_tailroom(skb) < RTA_ALIGN(rtalen)) goto nlmsg_failure; \
+   rta = (void*)__skb_put(skb, RTA_ALIGN(rtalen)); \
+   rta->rta_type = attrtype;                \
+   rta->rta_len = rtalen;                   \
+   RTA_DATA(rta); })
+
+static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
+			int ext, u32 pid, u32 seq)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct tcpdiagmsg *r;
+	struct nlmsghdr  *nlh;
+	struct tcp_info  *info = NULL;
+	struct tcpdiag_meminfo  *minfo = NULL;
+	unsigned char	 *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
+	r = NLMSG_DATA(nlh);
+	if (sk->state != TCP_TIME_WAIT) {
+		if (ext & (1<<(TCPDIAG_MEMINFO-1)))
+			minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo));
+		if (ext & (1<<(TCPDIAG_INFO-1)))
+			info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
+	}
+	r->tcpdiag_family = sk->family;
+	r->tcpdiag_state = sk->state;
+	r->tcpdiag_timer = 0;
+	r->tcpdiag_retrans = 0;
+
+	r->id.tcpdiag_sport = sk->sport;
+	r->id.tcpdiag_dport = sk->dport;
+	r->id.tcpdiag_src[0] = sk->rcv_saddr;
+	r->id.tcpdiag_dst[0] = sk->daddr;
+	r->id.tcpdiag_if = sk->bound_dev_if;
+	*((struct sock **)&r->id.tcpdiag_cookie) = sk;
+
+	if (r->tcpdiag_state == TCP_TIME_WAIT) {
+		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
+		long tmo = tw->ttd - jiffies;
+		if (tmo < 0)
+			tmo = 0;
+
+		r->tcpdiag_state = tw->substate;
+		r->tcpdiag_timer = 3;
+		r->tcpdiag_expires = (tmo*1000+HZ-1)/HZ;
+		r->tcpdiag_rqueue = 0;
+		r->tcpdiag_wqueue = 0;
+		r->tcpdiag_uid = 0;
+		r->tcpdiag_inode = 0;
+#ifdef CONFIG_IPV6
+		if (r->tcpdiag_family == AF_INET6) {
+			memcpy(r->id.tcpdiag_src, &tw->v6_rcv_saddr, 16);
+			memcpy(r->id.tcpdiag_dst, &tw->v6_daddr, 16);
+		}
+#endif
+		nlh->nlmsg_len = skb->tail - b;
+		return skb->len;
+	}
+
+#ifdef CONFIG_IPV6
+	if (r->tcpdiag_family == AF_INET6) {
+		memcpy(r->id.tcpdiag_src, &sk->net_pinfo.af_inet6.rcv_saddr, 16);
+		memcpy(r->id.tcpdiag_dst, &sk->net_pinfo.af_inet6.daddr, 16);
+	}
+#endif
+
+#define EXPIRES_IN_MS(tmo)  ((tmo-jiffies)*1000+HZ-1)/HZ
+
+	if (tp->pending == TCP_TIME_RETRANS) {
+		r->tcpdiag_timer = 1;
+		r->tcpdiag_retrans = tp->retransmits;
+		r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
+	} else if (tp->pending == TCP_TIME_PROBE0) {
+		r->tcpdiag_timer = 4;
+		r->tcpdiag_retrans = tp->probes_out;
+		r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
+	} else if (timer_pending(&sk->timer)) {
+		r->tcpdiag_timer = 2;
+		r->tcpdiag_retrans = tp->probes_out;
+		r->tcpdiag_expires = EXPIRES_IN_MS(sk->timer.expires);
+	} else {
+		r->tcpdiag_timer = 0;
+		r->tcpdiag_expires = 0;
+	}
+#undef EXPIRES_IN_MS
+
+	r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq;
+	r->tcpdiag_wqueue = tp->write_seq - tp->snd_una;
+	r->tcpdiag_uid = sock_i_uid(sk);
+	r->tcpdiag_inode = sock_i_ino(sk);
+
+	if (minfo) {
+		minfo->tcpdiag_rmem = atomic_read(&sk->rmem_alloc);
+		minfo->tcpdiag_wmem = sk->wmem_queued;
+		minfo->tcpdiag_fmem = sk->forward_alloc;
+		minfo->tcpdiag_tmem = atomic_read(&sk->wmem_alloc);
+	}
+
+	if (info) {
+		u32 now = tcp_time_stamp;
+
+		info->tcpi_state = sk->state;
+		info->tcpi_ca_state = tp->ca_state;
+		info->tcpi_retransmits = tp->retransmits;
+		info->tcpi_probes = tp->probes_out;
+		info->tcpi_backoff = tp->backoff;
+		info->tcpi_options = 0;
+		if (tp->tstamp_ok)
+			info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
+		if (tp->sack_ok)
+			info->tcpi_options |= TCPI_OPT_SACK;
+		if (tp->wscale_ok) {
+			info->tcpi_options |= TCPI_OPT_WSCALE;
+			info->tcpi_snd_wscale = tp->snd_wscale;
+			info->tcpi_rcv_wscale = tp->rcv_wscale;
+		} else {
+			info->tcpi_snd_wscale = 0;
+			info->tcpi_rcv_wscale = 0;
+		}
+#ifdef CONFIG_INET_ECN
+		if (tp->ecn_flags&TCP_ECN_OK)
+			info->tcpi_options |= TCPI_OPT_ECN;
+#endif
+
+		info->tcpi_rto = (1000000*tp->rto)/HZ;
+		info->tcpi_ato = (1000000*tp->ack.ato)/HZ;
+		info->tcpi_snd_mss = tp->mss_cache;
+		info->tcpi_rcv_mss = tp->ack.rcv_mss;
+
+		info->tcpi_unacked = tp->packets_out;
+		info->tcpi_sacked = tp->sacked_out;
+		info->tcpi_lost = tp->lost_out;
+		info->tcpi_retrans = tp->retrans_out;
+		info->tcpi_fackets = tp->fackets_out;
+
+		info->tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ;
+		info->tcpi_last_ack_sent = 0;
+		info->tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ;
+		info->tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ;
+
+		info->tcpi_pmtu = tp->pmtu_cookie;
+		info->tcpi_rcv_ssthresh = tp->rcv_ssthresh;
+		info->tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3;
+		info->tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2;
+		info->tcpi_snd_ssthresh = tp->snd_ssthresh;
+		info->tcpi_snd_cwnd = tp->snd_cwnd;
+		info->tcpi_advmss = tp->advmss;
+		info->tcpi_reordering = tp->reordering;
+	}
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+nlmsg_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
+#ifdef CONFIG_IPV6
+extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
+				  struct in6_addr *daddr, u16 dport,
+				  int dif);
+#endif
+
+static int tcpdiag_get_exact(struct sk_buff *in_skb, struct nlmsghdr *nlh)
+{
+	int err;
+	struct sock *sk;
+	struct tcpdiagreq *req = NLMSG_DATA(nlh);
+	struct sk_buff *rep;
+
+	if (req->tcpdiag_family == AF_INET) {
+		sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport,
+				   req->id.tcpdiag_src[0], req->id.tcpdiag_sport,
+				   req->id.tcpdiag_if);
+	}
+#ifdef CONFIG_IPV6
+	else if (req->tcpdiag_family == AF_INET6) {
+		sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport,
+				   (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport,
+				   req->id.tcpdiag_if);
+	}
+#endif
+	else {
+		return -EINVAL;
+	}
+
+	if (sk == NULL)
+		return -ENOENT;
+
+	err = -ESTALE;
+	if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
+	     req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
+	    sk != *((struct sock **)&req->id.tcpdiag_cookie[0]))
+		goto out;
+
+	err = -ENOMEM;
+	rep = alloc_skb(NLMSG_SPACE(sizeof(struct tcpdiagmsg)+
+				    sizeof(struct tcpdiag_meminfo)+
+				    sizeof(struct tcp_info)+64), GFP_KERNEL);
+	if (!rep)
+		goto out;
+
+	if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
+			 NETLINK_CB(in_skb).pid,
+			 nlh->nlmsg_seq) <= 0)
+		BUG();
+
+	err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+
+out:
+	if (sk) {
+		if (sk->state == TCP_TIME_WAIT)
+			tcp_tw_put((struct tcp_tw_bucket*)sk);
+		else
+			sock_put(sk);
+	}
+	return err;
+}
+
+int bitstring_match(u32 *a1, u32 *a2, int bits)
+{
+	int words = bits >> 5;
+
+	bits &= 0x1f;
+
+	if (words) {
+		if (memcmp(a1, a2, words << 2))
+			return 0;
+	}
+	if (bits) {
+		__u32 w1, w2;
+		__u32 mask;
+
+		w1 = a1[words];
+		w2 = a2[words];
+
+		mask = htonl((0xffffffff) << (32 - bits));
+
+		if ((w1 ^ w2) & mask)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+int tcpdiag_bc_run(char *bc, int len, struct sock *sk)
+{
+	while (len > 0) {
+		int yes = 1;
+		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
+
+		switch (op->code) {
+		case TCPDIAG_BC_NOP:
+			break;
+		case TCPDIAG_BC_JMP:
+			yes = 0;
+			break;
+		case TCPDIAG_BC_S_GE:
+			yes = (sk->num >= op[1].no);
+			break;
+		case TCPDIAG_BC_S_LE:
+			yes = (sk->num <= op[1].no);
+			break;
+		case TCPDIAG_BC_D_GE:
+			yes = (ntohs(sk->dport) >= op[1].no);
+			break;
+		case TCPDIAG_BC_D_LE:
+			yes = (ntohs(sk->dport) <= op[1].no);
+			break;
+		case TCPDIAG_BC_AUTO:
+			yes = !(sk->userlocks&SOCK_BINDPORT_LOCK);
+			break;
+		case TCPDIAG_BC_S_COND:
+		case TCPDIAG_BC_D_COND:
+		{
+			struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1);
+			u32 *addr;
+
+			if (cond->port != -1 &&
+			    cond->port != (op->code == TCPDIAG_BC_S_COND ? sk->num : ntohs(sk->dport))) {
+				yes = 0;
+				break;
+			}
+			
+			if (cond->prefix_len == 0)
+				break;
+
+#ifdef CONFIG_IPV6
+			if (sk->family == AF_INET6) {
+				if (op->code == TCPDIAG_BC_S_COND)
+					addr = (u32*)&sk->net_pinfo.af_inet6.rcv_saddr;
+				else
+					addr = (u32*)&sk->net_pinfo.af_inet6.daddr;
+			} else
+#endif
+			{
+				if (op->code == TCPDIAG_BC_S_COND)
+					addr = &sk->rcv_saddr;
+				else
+					addr = &sk->daddr;
+			}
+
+			if (bitstring_match(addr, cond->addr, cond->prefix_len))
+				break;
+			if (sk->family == AF_INET6 && cond->family == AF_INET) {
+				if (addr[0] == 0 && addr[1] == 0 &&
+				    addr[2] == __constant_htonl(0xffff) &&
+				    bitstring_match(addr+3, cond->addr, cond->prefix_len))
+					break;
+			}
+			yes = 0;
+			break;
+		}
+		}
+
+		if (yes) { 
+			len -= op->yes;
+			bc += op->yes;
+		} else {
+			len -= op->no;
+			bc += op->no;
+		}
+	}
+	return (len == 0);
+}
+
+int valid_cc(char *bc, int len, int cc)
+{
+	while (len >= 0) {
+		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
+
+		if (cc > len)
+			return 0;
+		if (cc == len)
+			return 1;
+		if (op->yes < 4)
+			return 0;
+		len -= op->yes;
+		bc  += op->yes;
+	}
+	return 0;
+}
+
+int tcpdiag_bc_audit(char *bytecode, int bytecode_len)
+{
+	char *bc = bytecode;
+	int  len = bytecode_len;
+
+	while (len > 0) {
+		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
+
+//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
+		switch (op->code) {
+		case TCPDIAG_BC_AUTO:
+		case TCPDIAG_BC_S_COND:
+		case TCPDIAG_BC_D_COND:
+		case TCPDIAG_BC_S_GE:
+		case TCPDIAG_BC_S_LE:
+		case TCPDIAG_BC_D_GE:
+		case TCPDIAG_BC_D_LE:
+			if (op->yes < 4 || op->yes > len+4)
+				return -EINVAL;
+		case TCPDIAG_BC_JMP:
+			if (op->no < 4 || op->no > len+4)
+				return -EINVAL;
+			if (op->no < len &&
+			    !valid_cc(bytecode, bytecode_len, len-op->no))
+				return -EINVAL;
+			break;
+		case TCPDIAG_BC_NOP:
+			if (op->yes < 4 || op->yes > len+4)
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		bc += op->yes;
+		len -= op->yes;
+	}
+	return len == 0 ? 0 : -EINVAL;
+}
+
+
+int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	int i, num;
+	int s_i, s_num;
+	struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
+	struct rtattr *bc = NULL;
+
+	if (cb->nlh->nlmsg_len > 4+NLMSG_SPACE(sizeof(struct tcpdiagreq)))
+		bc = (struct rtattr*)(r+1);
+
+	s_i = cb->args[1];
+	s_num = num = cb->args[2];
+
+	if (cb->args[0] == 0) {
+		if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV)))
+			goto skip_listen_ht;
+		tcp_listen_lock();
+		for (i = s_i; i < TCP_LHTABLE_SIZE; i++) {
+			struct sock *sk = tcp_listening_hash[i];
+
+			if (i > s_i)
+				s_num = 0;
+
+			for (sk = tcp_listening_hash[i], num = 0;
+			     sk != NULL;
+			     sk = sk->next, num++) {
+				if (num < s_num)
+					continue;
+				if (!(r->tcpdiag_states&TCPF_LISTEN) ||
+				    r->id.tcpdiag_dport)
+					continue;
+				if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport)
+					continue;
+				if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+					continue;
+				if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
+						 NETLINK_CB(cb->skb).pid,
+						 cb->nlh->nlmsg_seq) <= 0) {
+					tcp_listen_unlock();
+					goto done;
+				}
+			}
+		}
+		tcp_listen_unlock();
+skip_listen_ht:
+		cb->args[0] = 1;
+		s_i = num = s_num = 0;
+	}
+
+	if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV)))
+		return skb->len;
+
+	for (i = s_i; i < tcp_ehash_size; i++) {
+		struct tcp_ehash_bucket *head = &tcp_ehash[i];
+		struct sock *sk;
+
+		if (i > s_i)
+			s_num = 0;
+
+		read_lock_bh(&head->lock);
+
+		for (sk = head->chain, num = 0;
+		     sk != NULL;
+		     sk = sk->next, num++) {
+			if (num < s_num)
+				continue;
+			if (!(r->tcpdiag_states&(1<<sk->state)))
+				continue;
+			if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport)
+				continue;
+			if (r->id.tcpdiag_dport != sk->dport && r->id.tcpdiag_dport)
+				continue;
+			if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+				continue;
+			if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
+					 NETLINK_CB(cb->skb).pid,
+					 cb->nlh->nlmsg_seq) <= 0) {
+				read_unlock_bh(&head->lock);
+				goto done;
+			}
+		}
+
+		if (r->tcpdiag_states&TCPF_TIME_WAIT) {
+			for (sk = tcp_ehash[i+tcp_ehash_size].chain;
+			     sk != NULL;
+			     sk = sk->next, num++) {
+				if (num < s_num)
+					continue;
+				if (!(r->tcpdiag_states&(1<<sk->zapped)))
+					continue;
+				if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport)
+					continue;
+				if (r->id.tcpdiag_dport != sk->dport && r->id.tcpdiag_dport)
+					continue;
+				if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+					continue;
+				if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
+						 NETLINK_CB(cb->skb).pid,
+						 cb->nlh->nlmsg_seq) <= 0) {
+					read_unlock_bh(&head->lock);
+					goto done;
+				}
+			}
+		}
+		read_unlock_bh(&head->lock);
+	}
+
+done:
+	cb->args[1] = i;
+	cb->args[2] = num;
+	return skb->len;
+}
+
+static int tcpdiag_dump_done(struct netlink_callback *cb)
+{
+	return 0;
+}
+
+
+static __inline__ int
+tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
+		return 0;
+
+	if (nlh->nlmsg_type != TCPDIAG_GETSOCK)
+		goto err_inval;
+
+	if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len)
+		goto err_inval;
+
+	if (nlh->nlmsg_flags&NLM_F_DUMP) {
+		if (nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq))) {
+			struct rtattr *rta = (struct rtattr*)(NLMSG_DATA(nlh) + sizeof(struct tcpdiagreq));
+			if (rta->rta_type != TCPDIAG_REQ_BYTECODE ||
+			    rta->rta_len < 8 ||
+			    rta->rta_len > nlh->nlmsg_len - NLMSG_SPACE(sizeof(struct tcpdiagreq)))
+				goto err_inval;
+			if (tcpdiag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
+				goto err_inval;
+		}
+		return netlink_dump_start(tcpnl, skb, nlh,
+					  tcpdiag_dump,
+					  tcpdiag_dump_done);
+	} else {
+		return tcpdiag_get_exact(skb, nlh);
+	}
+
+err_inval:
+	return -EINVAL;
+}
+
+
+extern __inline__ void tcpdiag_rcv_skb(struct sk_buff *skb)
+{
+	int err;
+	struct nlmsghdr * nlh;
+
+	if (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *)skb->data;
+		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+			return;
+		err = tcpdiag_rcv_msg(skb, nlh);
+		if (err) 
+			netlink_ack(skb, nlh, err);
+	}
+}
+
+static void tcpdiag_rcv(struct sock *sk, int len)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+		tcpdiag_rcv_skb(skb);
+		kfree_skb(skb);
+	}
+}
+
+void __init tcpdiag_init(void)
+{
+	tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv);
+	if (tcpnl == NULL)
+		panic("tcpdiag_init: Cannot create netlink socket.");
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- linux-2.4.16/net/ipv4/tcp_input.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/tcp_input.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.238 2001/10/20 00:00:11 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.241 2001/11/14 02:48:51 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- linux-2.4.16/net/ipv4/tcp_ipv4.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/tcp_ipv4.c	Thu Dec  6 15:47:36 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.235 2001/10/26 14:51:13 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.237 2001/12/05 08:54:10 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -754,21 +754,19 @@
 }
 
 static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, 
-					      struct iphdr *iph,
-					      struct tcphdr *th,
-					      struct open_request ***prevp)
+					      struct open_request ***prevp,
+					      __u16 rport,
+					      __u32 raddr, __u32 laddr)
 {
 	struct tcp_listen_opt *lopt = tp->listen_opt;
 	struct open_request *req, **prev;  
-	__u16 rport = th->source;
-	__u32 raddr = iph->saddr;
 
 	for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport)];
 	     (req = *prev) != NULL;
 	     prev = &req->dl_next) {
 		if (req->rmt_port == rport &&
 		    req->af.v4_req.rmt_addr == raddr &&
-		    req->af.v4_req.loc_addr == iph->daddr &&
+		    req->af.v4_req.loc_addr == laddr &&
 		    TCP_INET_FAMILY(req->class->family)) {
 			BUG_TRAP(req->sk == NULL);
 			*prevp = prev;
@@ -939,7 +937,9 @@
 		if (sk->lock.users != 0)
 			goto out;
 
-		req = tcp_v4_search_req(tp, iph, th, &prev); 
+		req = tcp_v4_search_req(tp, &prev,
+					th->dest,
+					iph->daddr, iph->saddr); 
 		if (!req)
 			goto out;
 
@@ -1473,11 +1473,14 @@
 {
 	struct open_request *req, **prev;
 	struct tcphdr *th = skb->h.th;
+	struct iphdr *iph = skb->nh.iph;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sock *nsk;
 
 	/* Find possible connection requests. */
-	req = tcp_v4_search_req(tp, skb->nh.iph, th, &prev);
+	req = tcp_v4_search_req(tp, &prev,
+				th->source,
+				iph->saddr, iph->daddr);
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- linux-2.4.16/net/ipv4/tcp_output.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv4/tcp_output.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.143 2001/10/26 14:51:13 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.144 2001/11/06 22:21:08 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/Config.in linux/net/ipv6/Config.in
--- linux-2.4.16/net/ipv6/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/Config.in	Wed Dec  5 16:36:06 2001
@@ -1,11 +1,7 @@
 #
 # IPv6 configuration
 # 
-if [ "$CONFIG_NETLINK" = "y" ]; then
-   if [ "$CONFIG_RTNETLINK" = "n" ]; then
-      bool '    IPv6: routing messages via old netlink' CONFIG_IPV6_NETLINK
-   fi
-fi
+
 #bool '    IPv6: flow policy support' CONFIG_RT6_POLICY
 #bool '    IPv6: firewall support' CONFIG_IPV6_FIREWALL
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- linux-2.4.16/net/ipv6/addrconf.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/addrconf.c	Wed Dec  5 16:36:06 2001
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: addrconf.c,v 1.68 2001/09/01 00:31:50 davem Exp $
+ *	$Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1644,8 +1644,6 @@
 	mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY);
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static int
 inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
@@ -1806,13 +1804,11 @@
 	{ inet6_rtm_getroute,	inet6_dump_fib,		},
 	{ NULL,			NULL,			},
 };
-#endif
 
 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 {
-#ifdef CONFIG_RTNETLINK
 	inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
-#endif
+
 	switch (event) {
 	case RTM_NEWADDR:
 		ip6_rt_addr_add(&ifp->addr, ifp->idev->dev);
@@ -2021,9 +2017,7 @@
 	
 	addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
 	add_timer(&addr_chk_timer);
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
-#endif
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl.sysctl_header =
 		register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0);
@@ -2039,9 +2033,7 @@
  	struct inet6_ifaddr *ifa;
 	int i;
 
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_INET6] = NULL;
-#endif
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl_unregister(&ipv6_devconf_dflt);
 	addrconf_sysctl_unregister(&ipv6_devconf);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- linux-2.4.16/net/ipv6/ip6_fib.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/ip6_fib.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fib.c,v 1.24 2001/06/05 11:36:55 davem Exp $
+ *	$Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -466,9 +466,7 @@
 	*ins = rt;
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
-#ifdef CONFIG_RTNETLINK
 	inet6_rt_notify(RTM_NEWROUTE, rt);
-#endif
 	rt6_stats.fib_rt_entries++;
 
 	if ((fn->fn_flags & RTN_RTINFO) == 0) {
@@ -925,9 +923,7 @@
 		if (atomic_read(&rt->rt6i_ref) != 1) BUG();
 	}
 
-#ifdef CONFIG_RTNETLINK
 	inet6_rt_notify(RTM_DELROUTE, rt);
-#endif
 	rt6_release(rt);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c
--- linux-2.4.16/net/ipv6/ip6_fw.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/ip6_fw.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fw.c,v 1.15 1999/08/31 07:04:03 davem Exp $
+ *	$Id: ip6_fw.c,v 1.16 2001/10/31 08:17:58 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -379,16 +379,12 @@
 
 void __init ip6_fw_init(void)
 {
-#ifdef CONFIG_NETLINK
 	netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
-#endif
 }
 
 #ifdef MODULE
 void cleanup_module(void)
 {
-#ifdef CONFIG_NETLINK
 	netlink_detach(NETLINK_IP6_FW);
-#endif
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- linux-2.4.16/net/ipv6/ndisc.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/ndisc.c	Wed Dec  5 16:36:06 2001
@@ -1207,81 +1207,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-#ifndef CONFIG_RTNETLINK
-static int ndisc_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	int len=0;
-	off_t pos=0;
-	int size;
-	unsigned long now = jiffies;
-	int i;
-
-	for (i = 0; i <= NEIGH_HASHMASK; i++) {
-		struct neighbour *neigh;
-
-		read_lock_bh(&nd_tbl.lock);
-		for (neigh = nd_tbl.hash_buckets[i]; neigh; neigh = neigh->next) {
-			int j;
-
-			size = 0;
-			for (j=0; j<16; j++) {
-				sprintf(buffer+len+size, "%02x", neigh->primary_key[j]);
-				size += 2;
-			}
-
-			read_lock(&neigh->lock);
-			size += sprintf(buffer+len+size,
-				       " %02x %02x %02x %02x %08lx %08lx %08x %04x %04x %04x %8s ", i,
-				       128,
-				       neigh->type,
-				       neigh->nud_state,
-				       now - neigh->used,
-				       now - neigh->confirmed,
-				       neigh->parms->reachable_time,
-				       neigh->parms->gc_staletime,
-				       atomic_read(&neigh->refcnt) - 1,
-				       neigh->flags | (!neigh->hh ? 0 : (neigh->hh->hh_output==dev_queue_xmit ? 4 : 2)),
-				       neigh->dev->name);
-
-			if ((neigh->nud_state&NUD_VALID) && neigh->dev->addr_len) {
-				for (j=0; j < neigh->dev->addr_len; j++) {
-					sprintf(buffer+len+size, "%02x", neigh->ha[j]);
-					size += 2;
-				}
-			} else {
-                                size += sprintf(buffer+len+size, "000000000000");
-			}
-			read_unlock(&neigh->lock);
-			size += sprintf(buffer+len+size, "\n");
-			len += size;
-			pos += size;
-		  
-			if (pos <= offset)
-				len=0;
-			if (pos >= offset+length) {
-				read_unlock_bh(&nd_tbl.lock);
-				goto done;
-			}
-		}
-		read_unlock_bh(&nd_tbl.lock);
-	}
-
-done:
-
-	*start = buffer+len-(pos-offset);	/* Start of wanted data */
-	len = pos-offset;			/* Start slop */
-	if (len>length)
-		len = length;			/* Ending slop */
-	if (len<0)
-		len = 0;
-	return len;
-}
-
-#endif
-#endif	/* CONFIG_PROC_FS */
-
-
 int __init ndisc_init(struct net_proto_family *ops)
 {
 	struct sock *sk;
@@ -1319,11 +1244,6 @@
 	
 	neigh_table_init(&nd_tbl);
 
-#ifdef CONFIG_PROC_FS
-#ifndef CONFIG_RTNETLINK
-	proc_net_create("ndisc", 0, ndisc_get_info);
-#endif
-#endif
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
 #endif
@@ -1333,11 +1253,6 @@
 
 void ndisc_cleanup(void)
 {
-#ifdef CONFIG_PROC_FS
-#ifndef CONFIG_RTNETLINK
-        proc_net_remove("ndisc");
-#endif
-#endif
 	neigh_table_clear(&nd_tbl);
 	sock_release(ndisc_socket);
 	ndisc_socket = NULL; /* For safety. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/netfilter/Config.in linux/net/ipv6/netfilter/Config.in
--- linux-2.4.16/net/ipv6/netfilter/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/netfilter/Config.in	Wed Dec  5 16:36:06 2001
@@ -9,7 +9,7 @@
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 
-#if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 #  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
 #fi
 tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/route.c linux/net/ipv6/route.c
--- linux-2.4.16/net/ipv6/route.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/route.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.55 2001/09/18 22:29:10 davem Exp $
+ *	$Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1407,8 +1407,6 @@
 	read_unlock_bh(&rt6_lock);
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,
 			      struct in6_rtmsg *rtmsg)
 {
@@ -1740,8 +1738,6 @@
 	NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_ROUTE;
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_ROUTE, gfp_any());
 }
-
-#endif
 
 /*
  *	/proc
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- linux-2.4.16/net/ipv6/tcp_ipv6.c	Mon Nov 26 10:35:01 2001
+++ linux/net/ipv6/tcp_ipv6.c	Wed Dec  5 16:36:06 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.140 2001/10/15 12:34:50 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.142 2001/11/06 22:21:08 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/af_irda.c linux/net/irda/af_irda.c
--- linux-2.4.16/net/irda/af_irda.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/af_irda.c	Tue Dec  4 19:25:31 2001
@@ -914,8 +914,7 @@
 	memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));
 
 	/* Clean up the original one to keep it in listen state */
-	self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
-	self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+	irttp_listen(self->tsap);
 
 	skb->sk = NULL;
 	skb->destructor = NULL;
@@ -1845,15 +1844,36 @@
 		  	return -EFAULT;
 		}
 
-		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		/* Find the object we target.
+		 * If the user gives us an empty string, we use the object
+		 * associated with this socket. This will workaround
+		 * duplicated class name - Jean II */
+		if(ias_opt->irda_class_name[0] == '\0') {
+			if(self->ias_obj == NULL) {
+				kfree(ias_opt);
+				return -EINVAL;
+			}
+			ias_obj = self->ias_obj;
+		} else
+			ias_obj = irias_find_object(ias_opt->irda_class_name);
+
+		/* Only ROOT can mess with the global IAS database.
+		 * Users can only add attributes to the object associated
+		 * with the socket they own - Jean II */
+		if((!capable(CAP_NET_ADMIN)) &&
+		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
+			kfree(ias_opt);
+			return -EPERM;
+		}
+
+		/* If the object doesn't exist, create it */
 		if(ias_obj == (struct ias_object *) NULL) {
 			/* Create a new object */
 			ias_obj = irias_new_object(ias_opt->irda_class_name,
 						   jiffies);
 		}
 
-		/* Do we have it already ? */
+		/* Do we have the attribute already ? */
 		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
 			kfree(ias_opt);
 			return -EINVAL;
@@ -1927,13 +1947,28 @@
 		  	return -EFAULT;
 		}
 
-		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		/* Find the object we target.
+		 * If the user gives us an empty string, we use the object
+		 * associated with this socket. This will workaround
+		 * duplicated class name - Jean II */
+		if(ias_opt->irda_class_name[0] == '\0')
+			ias_obj = self->ias_obj;
+		else
+			ias_obj = irias_find_object(ias_opt->irda_class_name);
 		if(ias_obj == (struct ias_object *) NULL) {
 			kfree(ias_opt);
 			return -EINVAL;
 		}
 
+		/* Only ROOT can mess with the global IAS database.
+		 * Users can only del attributes from the object associated
+		 * with the socket they own - Jean II */
+		if((!capable(CAP_NET_ADMIN)) &&
+		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
+			kfree(ias_opt);
+			return -EPERM;
+		}
+
 		/* Find the attribute (in the object) we target */
 		ias_attr = irias_find_attrib(ias_obj,
 					     ias_opt->irda_attrib_name); 
@@ -2166,8 +2201,14 @@
 		  	return -EFAULT;
 		}
 
-		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		/* Find the object we target.
+		 * If the user gives us an empty string, we use the object
+		 * associated with this socket. This will workaround
+		 * duplicated class name - Jean II */
+		if(ias_opt->irda_class_name[0] == '\0')
+			ias_obj = self->ias_obj;
+		else
+			ias_obj = irias_find_object(ias_opt->irda_class_name);
 		if(ias_obj == (struct ias_object *) NULL) {
 			kfree(ias_opt);
 			return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/iriap.c linux/net/irda/iriap.c
--- linux-2.4.16/net/irda/iriap.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/iriap.c	Tue Dec  4 19:25:31 2001
@@ -800,9 +800,7 @@
 	new->max_header_size = max_header_size;
 
 	/* Clean up the original one to keep it in listen state */
-	self->lsap->dlsap_sel = LSAP_ANY;
-	self->lsap->lsap_state = LSAP_DISCONNECTED;
-	/* FIXME: refcount in irlmp might get wrong */
+	irlmp_listen(self->lsap);
 	
 	iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irlap.c linux/net/irda/irlap.c
--- linux-2.4.16/net/irda/irlap.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irlap.c	Tue Dec  4 19:25:31 2001
@@ -51,6 +51,11 @@
 hashbin_t *irlap = NULL;
 int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
 
+/* This is the delay of missed pf period before generating an event
+ * to the application. The spec mandate 3 seconds, but in some cases
+ * it's way too long. - Jean II */
+int sysctl_warn_noreply_time = 3;
+
 extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
 static void __irlap_close(struct irlap_cb *self);
 
@@ -527,22 +532,7 @@
 	self->discovery_cmd = discovery;
 	info.discovery = discovery;
 	
-	/* Check if the slot timeout is within limits */
-	if (sysctl_slot_timeout < 20) {
-		ERROR(__FUNCTION__ 
-		      "(), to low value for slot timeout!\n");
-		sysctl_slot_timeout = 20;
-	}
-	/* 
-	 * Highest value is actually 8, but we allow higher since
-	 * some devices seems to require it.
-	 */
-	if (sysctl_slot_timeout > 160) {
-		ERROR(__FUNCTION__ 
-		      "(), to high value for slot timeout!\n");
-		sysctl_slot_timeout = 160;
-	}
-	
+	/* sysctl_slot_timeout bounds are checked in irsysctl.c - Jean II */
 	self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
 	
 	irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
@@ -931,9 +921,6 @@
 	/* Set data size */
 	/*self->qos_rx.data_size.bits &= 0x03;*/
 
-	/* Set disconnect time -> done properly in qos.c */
-	/*self->qos_rx.link_disc_time.bits &= 0x07;*/
-
 	irda_qos_bits_to_value(&self->qos_rx);
 }
 
@@ -1070,8 +1057,11 @@
 	/*
 	 *  Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to 
 	 *  3 seconds otherwise. See page 71 in IrLAP for more details.
+	 *  Actually, it's not always 3 seconds, as we allow to set
+	 *  it via sysctl... Max maxtt is 500ms, and N1 need to be multiple
+	 *  of 2, so 1 second is minimum we can allow. - Jean II
 	 */
-	if (self->qos_tx.link_disc_time.value == 3)
+	if (self->qos_tx.link_disc_time.value == sysctl_warn_noreply_time)
 		/* 
 		 * If we set N1 to 0, it will trigger immediately, which is
 		 * not what we want. What we really want is to disable it,
@@ -1079,7 +1069,8 @@
 		 */
 		self->N1 = -2; /* Disable - Need to be multiple of 2*/
 	else
-		self->N1 = 3000 / self->qos_rx.max_turn_time.value;
+		self->N1 = sysctl_warn_noreply_time * 1000 /
+		  self->qos_rx.max_turn_time.value;
 	
 	IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- linux-2.4.16/net/irda/irlap_event.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irlap_event.c	Tue Dec  4 19:25:31 2001
@@ -1405,30 +1405,29 @@
 		}
 		self->add_wait = FALSE;
 
-		if ((self->retry_count < self->N2) && 
-		    (self->retry_count != self->N1)) {
-			
+		/* N2 is the disconnect timer. Until we reach it, we retry */
+		if (self->retry_count < self->N2) {
+			/* Retry sending the pf bit to the secondary */
 			irlap_wait_min_turn_around(self, &self->qos_tx);
 			irlap_send_rr_frame(self, CMD_FRAME);
 			
 			irlap_start_final_timer(self, self->final_timeout);
 		 	self->retry_count++;
-
 			IRDA_DEBUG(4, "irlap_state_nrm_p: FINAL_TIMER_EXPIRED:"
 				   " retry_count=%d\n", self->retry_count);
-			/* Keep state */
-		} else if (self->retry_count == self->N1) {
-			irlap_status_indication(self, STATUS_NO_ACTIVITY);
-			irlap_wait_min_turn_around(self, &self->qos_tx);
-			irlap_send_rr_frame(self, CMD_FRAME);
-			
-			irlap_start_final_timer(self, self->final_timeout);
-			self->retry_count++;
 
-			IRDA_DEBUG(4, "retry count = N1; retry_count=%d\n", 
-				   self->retry_count);
+			/* Early warning event. I'm using a pretty liberal
+			 * interpretation of the spec and generate an event
+			 * every time the timer is multiple of N1 (and not
+			 * only the first time). This allow application
+			 * to know precisely if connectivity restart...
+			 * Jean II */
+			if((self->retry_count % self->N1) == 0)
+				irlap_status_indication(self,
+							STATUS_NO_ACTIVITY);
+
 			/* Keep state */
-		} else if (self->retry_count >= self->N2) {
+		} else {
 			irlap_apply_default_connection_parameters(self);
 
 			/* Always switch state before calling upper layers */
@@ -1991,6 +1990,7 @@
 		 *  Wait until retry_count * n matches negotiated threshold/
 		 *  disconnect time (note 2 in IrLAP p. 82)
 		 *
+		 * Similar to irlap_state_nrm_p() -> FINAL_TIMER_EXPIRED
 		 * Note : self->wd_timeout = (self->final_timeout * 2),
 		 *   which explain why we use (self->N2 / 2) here !!!
 		 * Jean II
@@ -1998,16 +1998,15 @@
 		IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n", 
 			   self->retry_count);
 
-		if ((self->retry_count <  (self->N2 / 2))  && 
-		    (self->retry_count != (self->N1 / 2))) {
-			
+		if (self->retry_count < (self->N2 / 2)) {
+			/* No retry, just wait for primary */
 			irlap_start_wd_timer(self, self->wd_timeout);
 			self->retry_count++;
-		} else if (self->retry_count == (self->N1 / 2)) {
-			irlap_status_indication(self, STATUS_NO_ACTIVITY);
-			irlap_start_wd_timer(self, self->wd_timeout);
-			self->retry_count++;
-		} else if (self->retry_count >= (self->N2 / 2)) {
+
+			if((self->retry_count % (self->N1 / 2)) == 0)
+				irlap_status_indication(self,
+							STATUS_NO_ACTIVITY);
+		} else {
 			irlap_apply_default_connection_parameters(self);
 			
 			/* Always switch state before calling upper layers */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irlmp.c linux/net/irda/irlmp.c
--- linux-2.4.16/net/irda/irlmp.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irlmp.c	Tue Dec  4 19:25:31 2001
@@ -469,7 +469,12 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
 		   self->slsap_sel, self->dlsap_sel);
-	
+
+	/* Note : self->lap is set in irlmp_link_data_indication(),
+	 * (case CONNECT_CMD:) because we have no way to set it here.
+	 * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap().
+	 * Jean II */
+
 	self->qos = *self->lap->qos;
 
 	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
@@ -577,7 +582,9 @@
 	/* Dup */
 	memcpy(new, orig, sizeof(struct lsap_cb));
 	new->notify.instance = instance;
-	
+	/* new->lap = orig->lap; => done in the memcpy() */
+	/* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */
+
 	init_timer(&new->watchdog_timer);
 	
 	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (int) new, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- linux-2.4.16/net/irda/irlmp_event.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irlmp_event.c	Tue Dec  4 19:25:31 2001
@@ -407,12 +407,7 @@
 		 *  removed later and moved to the list of unconnected LSAPs
 		 */
 		if (HASHBIN_GET_SIZE(self->lsaps) > 0) {
-			/* Make sure the timer has sensible value (the user
-			 * may have set it) - Jean II */
-			if(sysctl_lap_keepalive_time < 100)	/* 100ms */
-				sysctl_lap_keepalive_time = 100;
-			if(sysctl_lap_keepalive_time > 10000)	/* 10s */
-				sysctl_lap_keepalive_time = 10000;
+			/* Timer value is checked in irsysctl - Jean II */
 			irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);
 		} else {
 			/* No more connections, so close IrLAP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h
--- linux-2.4.16/net/irda/irnet/irnet.h	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irnet/irnet.h	Tue Dec  4 19:25:31 2001
@@ -199,6 +199,13 @@
  *	o Avoid leaking discovery log and skb
  *	o Replace "self" with "server" in irnet_connect_indication() to
  *	  better detect cut'n'paste error ;-)
+ *
+ * v9 - 29.11.01 - Jean II
+ *	o Fix event generation in disconnect indication that I broke in v8
+ *	  It was always generation "No-Answer" because I was testing ttp_open
+ *	  just after clearing it. *blush*.
+ *	o Use newly created irttp_listen() to fix potential crash when LAP
+ *	  destroyed before irnet module removed.
  */
 
 /***************************** INCLUDES *****************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- linux-2.4.16/net/irda/irnet/irnet_irda.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irnet/irnet_irda.c	Tue Dec  4 19:25:31 2001
@@ -830,8 +830,7 @@
 #endif /* STREAM_COMPAT */
 
   /* Clean up the original one to keep it in listen state */
-  server->tsap->dtsap_sel = server->tsap->lsap->dlsap_sel = LSAP_ANY;
-  server->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+  irttp_listen(server->tsap);
 
   /* Send a connection response on the new socket */
   irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);
@@ -897,8 +896,7 @@
 		   self->saddr, self->daddr, self->rname);
 
   /* Clean up the server to keep it in listen state */
-  self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
-  self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+  irttp_listen(self->tsap);
 
   DEXIT(IRDA_SERV_TRACE, "\n");
   return;
@@ -1081,7 +1079,8 @@
 			    struct sk_buff *skb)
 {
   irnet_socket *	self = (irnet_socket *) instance;
-  int			test = 0;
+  int			test_open;
+  int			test_connect;
 
   DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
   DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
@@ -1091,23 +1090,23 @@
     dev_kfree_skb(skb);
 
   /* Prevent higher layer from accessing IrTTP */
-  test = test_and_clear_bit(0, &self->ttp_open);
+  test_open = test_and_clear_bit(0, &self->ttp_open);
   /* Not connecting anymore...
    * (note : TSAP is open, so IAP callbacks are no longer pending...) */
-  test |= test_and_clear_bit(0, &self->ttp_connect);
+  test_connect = test_and_clear_bit(0, &self->ttp_connect);
 
   /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we
    * have a race condition with irda_irnet_destroy() or
    * irnet_connect_indication(), so don't mess up tsap...
    */
-  if(!test)
+  if(!(test_open || test_connect))
     {
       DERROR(IRDA_CB_ERROR, "Race condition detected...\n");
       return;
     }
 
   /* If we were active, notify the control channel */
-  if(test_bit(0, &self->ttp_open))
+  if(test_open)
     irnet_post_event(self, IRNET_DISCONNECT_FROM,
 		     self->saddr, self->daddr, self->rname);
   else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- linux-2.4.16/net/irda/irsysctl.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/irsysctl.c	Tue Dec  4 19:25:31 2001
@@ -10,6 +10,7 @@
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -32,24 +33,47 @@
 #include <net/irda/irias_object.h>
 
 #define NET_IRDA 412 /* Random number */
-enum { DISCOVERY=1, DEVNAME, DEBUG, SLOTS, DISCOVERY_TIMEOUT, 
-       SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME, LAP_KEEPALIVE_TIME, };
+enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
+       DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
+       MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, LAP_KEEPALIVE_TIME };
 
 extern int  sysctl_discovery;
 extern int  sysctl_discovery_slots;
 extern int  sysctl_discovery_timeout;
-extern int  sysctl_slot_timeout;
+extern int  sysctl_slot_timeout;	/* Candidate */
 extern int  sysctl_fast_poll_increase;
 int         sysctl_compression = 0;
 extern char sysctl_devname[];
 extern int  sysctl_max_baud_rate;
-extern int  sysctl_max_inactive_time;
+extern int  sysctl_min_tx_turn_time;
+extern int  sysctl_max_noreply_time;
+extern int  sysctl_warn_noreply_time;
 extern int  sysctl_lap_keepalive_time;
 
 #ifdef CONFIG_IRDA_DEBUG
 extern unsigned int irda_debug;
 #endif
 
+/* this is needed for the proc_dointvec_minmax - Jean II */
+static int max_discovery_slots = 16;		/* ??? */
+static int min_discovery_slots = 1;
+/* IrLAP 6.13.2 says 25ms to 10+70ms - allow higher since some devices
+ * seems to require it. (from Dag's comment) */
+static int max_slot_timeout = 160;
+static int min_slot_timeout = 20;
+static int max_max_baud_rate = 16000000;	/* See qos.c - IrLAP spec */
+static int min_max_baud_rate = 2400;
+static int max_min_tx_turn_time = 10000;	/* See qos.c - IrLAP spec */
+static int min_min_tx_turn_time = 0;
+static int max_max_noreply_time = 40;		/* See qos.c - IrLAP spec */
+static int min_max_noreply_time = 3;
+static int max_warn_noreply_time = 3;		/* 3s == standard */
+static int min_warn_noreply_time = 1;		/* 1s == min WD_TIMER */
+static int max_lap_keepalive_time = 10000;	/* 10s */
+static int min_lap_keepalive_time = 100;	/* 100us */
+/* For other sysctl, I've no idea of the range. Maybe Dag could help
+ * us on that - Jean II */
+
 static int do_devname(ctl_table *table, int write, struct file *filp,
 		      void *buffer, size_t *lenp)
 {
@@ -77,21 +101,32 @@
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 #endif
 #ifdef CONFIG_IRDA_FAST_RR
-        { SLOTS, "fast_poll_increase", &sysctl_fast_poll_increase,
+        { FAST_POLL, "fast_poll_increase", &sysctl_fast_poll_increase,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 #endif
-	{ SLOTS, "discovery_slots", &sysctl_discovery_slots,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	{ DISCOVERY_SLOTS, "discovery_slots", &sysctl_discovery_slots,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_discovery_slots, &max_discovery_slots },
 	{ DISCOVERY_TIMEOUT, "discovery_timeout", &sysctl_discovery_timeout,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ SLOT_TIMEOUT, "slot_timeout", &sysctl_slot_timeout,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_slot_timeout, &max_slot_timeout },
 	{ MAX_BAUD_RATE, "max_baud_rate", &sysctl_max_baud_rate,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
-	{ MAX_INACTIVE_TIME, "max_inactive_time", &sysctl_max_inactive_time,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_baud_rate, &max_max_baud_rate },
+	{ MIN_TX_TURN_TIME, "min_tx_turn_time", &sysctl_min_tx_turn_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_min_tx_turn_time, &max_min_tx_turn_time },
+	{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_noreply_time, &max_max_noreply_time },
+	{ WARN_NOREPLY_TIME, "warn_noreply_time", &sysctl_warn_noreply_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_warn_noreply_time, &max_warn_noreply_time },
 	{ LAP_KEEPALIVE_TIME, "lap_keepalive_time", &sysctl_lap_keepalive_time,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_lap_keepalive_time, &max_lap_keepalive_time },
 	{ 0 }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/irda/qos.c linux/net/irda/qos.c
--- linux-2.4.16/net/irda/qos.c	Mon Nov 26 10:35:01 2001
+++ linux/net/irda/qos.c	Tue Dec  4 19:25:31 2001
@@ -51,7 +51,16 @@
  * may want to keep the LAP alive longuer or shorter in case of link failure.
  * Remember that the threshold time (early warning) is fixed to 3s...
  */
-int sysctl_max_inactive_time = 12;
+int sysctl_max_noreply_time = 12;
+/*
+ * Minimum turn time to be applied before transmitting to the peer.
+ * Nonzero values (usec) are used as lower limit to the per-connection
+ * mtt value which was announced by the other end during negotiation.
+ * Might be helpful if the peer device provides too short mtt.
+ * Default is 10 which means using the unmodified value given by the peer
+ * except if it's 0 (0 is likely a bug in the other stack).
+ */
+unsigned sysctl_min_tx_turn_time = 10;
 
 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
 static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, 
@@ -184,7 +193,6 @@
  * Function value_lower_bits (value, array)
  *
  *    Returns a bit field marking all possibility lower than value.
- *    We may need a "value_higher_bits" in the future...
  */
 static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field)
 {
@@ -207,6 +215,33 @@
 	return i;
 }
 
+/*
+ * Function value_highest_bit (value, array)
+ *
+ *    Returns a bit field marking the highest possibility lower than value.
+ */
+static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field)
+{
+	int	i;
+	__u16	mask = 0x1;
+	__u16	result = 0x0;
+
+	for (i=0; i < size; i++) {
+		/* Finished ? */
+		if (array[i] <= value)
+			break;
+		/* Shift mask */
+		mask <<= 1;
+	}
+	/* Set the current value to the bit field */
+	result |= mask;
+	/* Send back a valid index */
+	if(i >= size)
+	  i = size - 1;	/* Last item */
+	*field = result;
+	return i;
+}
+
 /* -------------------------- MAIN CALLS -------------------------- */
 
 /*
@@ -254,9 +289,9 @@
 	sysctl_max_baud_rate = index_value(i, baud_rates);
 
 	/* Set configured max disc time */
-	i = value_lower_bits(sysctl_max_inactive_time, link_disc_times, 8,
+	i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8,
 			     &qos->link_disc_time.bits);
-	sysctl_max_inactive_time = index_value(i, link_disc_times);
+	sysctl_max_noreply_time = index_value(i, link_disc_times);
 
 	/* LSB is first byte, MSB is second byte */
 	qos->baud_rate.bits    &= 0x03ff;
@@ -281,6 +316,19 @@
 	int index;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/*
+	 * Make sure the mintt is sensible.
+	 */
+	if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
+		int i;
+
+		/* We don't really need bits, but easier this way */
+		i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
+				      8, &qos->min_turn_time.bits);
+		sysctl_min_tx_turn_time = index_value(i, min_turn_times);
+		qos->min_turn_time.value = sysctl_min_tx_turn_time;
+	}
 
 	/* 
 	 * Not allowed to use a max turn time less than 500 ms if the baudrate
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c
--- linux-2.4.16/net/netlink/netlink_dev.c	Mon Nov 26 10:35:01 2001
+++ linux/net/netlink/netlink_dev.c	Wed Dec  5 16:36:06 2001
@@ -195,11 +195,13 @@
 	/*  Someone tell me the official names for the uppercase ones  */
 	make_devfs_entries ("route", 0);
 	make_devfs_entries ("skip", 1);
-	make_devfs_entries ("USERSOCK", 2);
+	make_devfs_entries ("usersock", 2);
 	make_devfs_entries ("fwmonitor", 3);
-	make_devfs_entries ("ARPD", 8);
-	make_devfs_entries ("ROUTE6", 11);
-	make_devfs_entries ("IP6_FW", 13);
+	make_devfs_entries ("tcpdiag", 4);
+	make_devfs_entries ("arpd", 8);
+	make_devfs_entries ("route6", 11);
+	make_devfs_entries ("ip6_fw", 13);
+	make_devfs_entries ("dnrtmsg", 13);
 	devfs_register_series (devfs_handle, "tap%u", 16, DEVFS_FL_DEFAULT,
 			       NETLINK_MAJOR, 16,
 			       S_IFCHR | S_IRUSR | S_IWUSR,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/netsyms.c linux/net/netsyms.c
--- linux-2.4.16/net/netsyms.c	Mon Nov 26 10:35:01 2001
+++ linux/net/netsyms.c	Wed Dec  5 16:36:05 2001
@@ -116,6 +116,7 @@
 EXPORT_SYMBOL(sk_free);
 EXPORT_SYMBOL(sock_wake_async);
 EXPORT_SYMBOL(sock_alloc_send_skb);
+EXPORT_SYMBOL(sock_alloc_send_pskb);
 EXPORT_SYMBOL(sock_init_data);
 EXPORT_SYMBOL(sock_no_release);
 EXPORT_SYMBOL(sock_no_bind);
@@ -406,7 +407,6 @@
 
 #endif
 
-#ifdef CONFIG_NETLINK
 EXPORT_SYMBOL(netlink_set_err);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_unicast);
@@ -418,9 +418,7 @@
 EXPORT_SYMBOL(netlink_detach);
 EXPORT_SYMBOL(netlink_post);
 #endif
-#endif
 
-#ifdef CONFIG_RTNETLINK
 EXPORT_SYMBOL(rtattr_parse);
 EXPORT_SYMBOL(rtnetlink_links);
 EXPORT_SYMBOL(__rta_fill);
@@ -430,7 +428,6 @@
 EXPORT_SYMBOL(neigh_delete);
 EXPORT_SYMBOL(neigh_add);
 EXPORT_SYMBOL(neigh_dump_info);
-#endif
 
 EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
@@ -553,9 +550,7 @@
 EXPORT_SYMBOL(tcf_police);
 EXPORT_SYMBOL(tcf_police_locate);
 EXPORT_SYMBOL(tcf_police_destroy);
-#ifdef CONFIG_RTNETLINK
 EXPORT_SYMBOL(tcf_police_dump);
-#endif
 #endif
 #endif
 #ifdef CONFIG_NET_CLS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/packet/af_packet.c linux/net/packet/af_packet.c
--- linux-2.4.16/net/packet/af_packet.c	Mon Nov 26 10:35:01 2001
+++ linux/net/packet/af_packet.c	Thu Dec  6 15:47:36 2001
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.57 2001/10/30 03:38:37 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.58 2001/11/28 21:02:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1902,3 +1902,4 @@
 
 module_init(packet_init);
 module_exit(packet_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/Config.in linux/net/sched/Config.in
--- linux-2.4.16/net/sched/Config.in	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/Config.in	Wed Dec  5 16:36:06 2001
@@ -1,8 +1,6 @@
 #
 # Traffic control configuration.
 # 
-define_bool CONFIG_NETLINK y
-define_bool CONFIG_RTNETLINK y	
 tristate '  CBQ packet scheduler' CONFIG_NET_SCH_CBQ
 tristate '  CSZ packet scheduler' CONFIG_NET_SCH_CSZ
 #tristate '  H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/cls_api.c linux/net/sched/cls_api.c
--- linux-2.4.16/net/sched/cls_api.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/cls_api.c	Wed Dec  5 16:36:06 2001
@@ -97,8 +97,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
 			  struct tcf_proto *tp, unsigned long fh, int event);
 
@@ -430,12 +428,9 @@
 	return skb->len;
 }
 
-#endif
-
 
 int __init tc_filter_init(void)
 {
-#ifdef CONFIG_RTNETLINK
 	struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC];
 
 	/* Setup rtnetlink links. It is made here to avoid
@@ -448,7 +443,6 @@
 		link_p[RTM_GETTFILTER-RTM_BASE].doit = tc_ctl_tfilter;
 		link_p[RTM_GETTFILTER-RTM_BASE].dumpit = tc_dump_tfilter;
 	}
-#endif
 #define INIT_TC_FILTER(name) { \
           extern struct tcf_proto_ops cls_##name##_ops; \
           register_tcf_proto_ops(&cls_##name##_ops); \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/cls_fw.c linux/net/sched/cls_fw.c
--- linux-2.4.16/net/sched/cls_fw.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/cls_fw.c	Wed Dec  5 16:36:06 2001
@@ -299,7 +299,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int fw_dump(struct tcf_proto *tp, unsigned long fh,
 		   struct sk_buff *skb, struct tcmsg *t)
 {
@@ -350,8 +349,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
-
 
 struct tcf_proto_ops cls_fw_ops = {
 	NULL,
@@ -365,11 +362,7 @@
 	fw_change,
 	fw_delete,
 	fw_walk,
-#ifdef CONFIG_RTNETLINK
 	fw_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/cls_route.c linux/net/sched/cls_route.c
--- linux-2.4.16/net/sched/cls_route.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/cls_route.c	Wed Dec  5 16:36:06 2001
@@ -550,7 +550,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int route4_dump(struct tcf_proto *tp, unsigned long fh,
 		       struct sk_buff *skb, struct tcmsg *t)
 {
@@ -606,7 +605,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct tcf_proto_ops cls_route4_ops = {
 	NULL,
@@ -620,11 +618,7 @@
 	route4_change,
 	route4_delete,
 	route4_walk,
-#ifdef CONFIG_RTNETLINK
 	route4_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h
--- linux-2.4.16/net/sched/cls_rsvp.h	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/cls_rsvp.h	Wed Dec  5 16:36:06 2001
@@ -615,7 +615,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
 		     struct sk_buff *skb, struct tcmsg *t)
 {
@@ -672,7 +671,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct tcf_proto_ops RSVP_OPS = {
 	NULL,
@@ -686,11 +684,7 @@
 	rsvp_change,
 	rsvp_delete,
 	rsvp_walk,
-#ifdef CONFIG_RTNETLINK
 	rsvp_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c
--- linux-2.4.16/net/sched/cls_tcindex.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/cls_tcindex.c	Wed Dec  5 16:36:06 2001
@@ -421,8 +421,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
     struct sk_buff *skb, struct tcmsg *t)
 {
@@ -481,9 +479,6 @@
 	return -1;
 }
 
-#endif
-
-
 struct tcf_proto_ops cls_tcindex_ops = {
 	NULL,
 	"tcindex",
@@ -496,11 +491,7 @@
 	tcindex_change,
 	tcindex_delete,
 	tcindex_walk,
-#ifdef CONFIG_RTNETLINK
 	tcindex_dump
-#else
-	NULL
-#endif
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/cls_u32.c linux/net/sched/cls_u32.c
--- linux-2.4.16/net/sched/cls_u32.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/cls_u32.c	Wed Dec  5 16:36:06 2001
@@ -635,7 +635,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int u32_dump(struct tcf_proto *tp, unsigned long fh,
 		     struct sk_buff *skb, struct tcmsg *t)
 {
@@ -694,7 +693,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct tcf_proto_ops cls_u32_ops = {
 	NULL,
@@ -708,11 +706,7 @@
 	u32_change,
 	u32_delete,
 	u32_walk,
-#ifdef CONFIG_RTNETLINK
 	u32_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/police.c linux/net/sched/police.c
--- linux-2.4.16/net/sched/police.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/police.c	Wed Dec  5 16:36:06 2001
@@ -219,7 +219,6 @@
 	return p->action;
 }
 
-#ifdef CONFIG_RTNETLINK
 int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p)
 {
 	unsigned char	 *b = skb->tail;
@@ -250,5 +249,3 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_api.c linux/net/sched/sch_api.c
--- linux-2.4.16/net/sched/sch_api.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_api.c	Wed Dec  5 16:36:06 2001
@@ -41,12 +41,10 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#ifdef CONFIG_RTNETLINK
 static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
 			struct Qdisc *old, struct Qdisc *new);
 static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
 			 struct Qdisc *q, unsigned long cl, int event);
-#endif
 
 /*
 
@@ -379,8 +377,6 @@
 	return err;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 /*
    Allocate and initialize new qdisc.
 
@@ -1055,7 +1051,6 @@
 	dev_put(dev);
 	return skb->len;
 }
-#endif
 
 int psched_us_per_tick = 1;
 int psched_tick_per_us = 1;
@@ -1169,9 +1164,7 @@
 
 int __init pktsched_init(void)
 {
-#ifdef CONFIG_RTNETLINK
 	struct rtnetlink_link *link_p;
-#endif
 
 #if PSCHED_CLOCK_SOURCE == PSCHED_CPU
 	if (psched_calibrate_clock() < 0)
@@ -1184,7 +1177,6 @@
 #endif
 #endif
 
-#ifdef CONFIG_RTNETLINK
 	link_p = rtnetlink_links[PF_UNSPEC];
 
 	/* Setup rtnetlink links. It is made here to avoid
@@ -1201,7 +1193,6 @@
 		link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;
 		link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;
 	}
-#endif
 
 #define INIT_QDISC(name) { \
           extern struct Qdisc_ops name##_qdisc_ops; \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_atm.c linux/net/sched/sch_atm.c
--- linux-2.4.16/net/sched/sch_atm.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_atm.c	Wed Dec  5 16:36:06 2001
@@ -619,8 +619,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
     struct sk_buff *skb, struct tcmsg *tcm)
 {
@@ -668,9 +666,6 @@
 	return 0;
 }
 
-#endif
-
-
 static struct Qdisc_class_ops atm_class_ops =
 {
 	atm_tc_graft,			/* graft */
@@ -685,9 +680,7 @@
 	atm_tc_bind_filter,		/* bind_tcf */
 	atm_tc_put,			/* unbind_tcf */
 
-#ifdef CONFIG_RTNETLINK
 	atm_tc_dump_class,		/* dump */
-#endif
 };
 
 struct Qdisc_ops atm_qdisc_ops =
@@ -707,9 +700,7 @@
 	atm_tc_destroy,			/* destroy */
 	NULL,				/* change */
 
-#ifdef CONFIG_RTNETLINK
 	atm_tc_dump			/* dump */
-#endif
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- linux-2.4.16/net/sched/sch_cbq.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_cbq.c	Wed Dec  5 16:36:06 2001
@@ -1457,8 +1457,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
 {
 	unsigned char	 *b = skb->tail;
@@ -1658,8 +1656,6 @@
 	return -1;
 }
 
-#endif
-
 static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 		     struct Qdisc **old)
 {
@@ -2082,9 +2078,7 @@
 	cbq_bind_filter,
 	cbq_unbind_filter,
 
-#ifdef CONFIG_RTNETLINK
 	cbq_dump_class,
-#endif
 };
 
 struct Qdisc_ops cbq_qdisc_ops =
@@ -2104,9 +2098,7 @@
 	cbq_destroy,
 	NULL /* cbq_change */,
 
-#ifdef CONFIG_RTNETLINK
 	cbq_dump,
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_csz.c linux/net/sched/sch_csz.c
--- linux-2.4.16/net/sched/sch_csz.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_csz.c	Wed Dec  5 16:36:06 2001
@@ -795,7 +795,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int csz_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct csz_sched_data *q = (struct csz_sched_data *)sch->data;
@@ -817,8 +816,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
-
 
 static int csz_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
 		     struct Qdisc **old)
@@ -932,7 +929,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int csz_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm)
 {
 	struct csz_sched_data *q = (struct csz_sched_data *)sch->data;
@@ -978,7 +974,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static void csz_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 {
@@ -1030,9 +1025,7 @@
 	csz_bind,
 	csz_put,
 
-#ifdef CONFIG_RTNETLINK
 	csz_dump_class,
-#endif
 };
 
 struct Qdisc_ops csz_qdisc_ops =
@@ -1052,9 +1045,7 @@
 	csz_destroy,
 	NULL /* csz_change */,
 
-#ifdef CONFIG_RTNETLINK
 	csz_dump,
-#endif
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_dsmark.c linux/net/sched/sch_dsmark.c
--- linux-2.4.16/net/sched/sch_dsmark.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_dsmark.c	Wed Dec  5 16:36:06 2001
@@ -385,8 +385,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
     struct sk_buff *skb, struct tcmsg *tcm)
 {
@@ -434,9 +432,6 @@
 	return -1;
 }
 
-#endif
-
-
 static struct Qdisc_class_ops dsmark_class_ops =
 {
 	dsmark_graft,			/* graft */
@@ -451,9 +446,7 @@
 	dsmark_bind_filter,		/* bind_tcf */
 	dsmark_put,			/* unbind_tcf */
 
-#ifdef CONFIG_RTNETLINK
 	dsmark_dump_class,		/* dump */
-#endif
 };
 
 struct Qdisc_ops dsmark_qdisc_ops =
@@ -473,9 +466,7 @@
 	dsmark_destroy,			/* destroy */
 	NULL,				/* change */
 
-#ifdef CONFIG_RTNETLINK
 	dsmark_dump			/* dump */
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_fifo.c linux/net/sched/sch_fifo.c
--- linux-2.4.16/net/sched/sch_fifo.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_fifo.c	Wed Dec  5 16:36:06 2001
@@ -152,7 +152,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct fifo_sched_data *q = (void*)sch->data;
@@ -168,7 +167,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct Qdisc_ops pfifo_qdisc_ops =
 {
@@ -187,9 +185,7 @@
 	NULL,
 	fifo_init,
 
-#ifdef CONFIG_RTNETLINK
 	fifo_dump,
-#endif
 };
 
 struct Qdisc_ops bfifo_qdisc_ops =
@@ -208,7 +204,5 @@
 	fifo_reset,
 	NULL,
 	fifo_init,
-#ifdef CONFIG_RTNETLINK
 	fifo_dump,
-#endif
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_gred.c linux/net/sched/sch_gred.c
--- linux-2.4.16/net/sched/sch_gred.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_gred.c	Wed Dec  5 16:36:06 2001
@@ -494,7 +494,6 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	unsigned long qave;
@@ -587,7 +586,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static void gred_destroy(struct Qdisc *sch)
 {
@@ -615,9 +613,7 @@
 	gred_reset,
 	gred_destroy,
 	gred_change, /* change */
-#ifdef CONFIG_RTNETLINK
 	gred_dump,
-#endif
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_ingress.c linux/net/sched/sch_ingress.c
--- linux-2.4.16/net/sched/sch_ingress.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_ingress.c	Wed Dec  5 16:36:06 2001
@@ -304,9 +304,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
-
 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	unsigned char *b = skb->tail;
@@ -322,9 +319,6 @@
 	return -1;
 }
 
-#endif
-
-
 static struct Qdisc_class_ops ingress_class_ops =
 {
 	ingress_graft,			/* graft */
@@ -339,9 +333,7 @@
 	ingress_bind_filter,		/* bind_tcf */
 	ingress_put,			/* unbind_tcf */
 
-#ifdef CONFIG_RTNETLINK
 	NULL,		/* dump */
-#endif
 };
 
 struct Qdisc_ops ingress_qdisc_ops =
@@ -361,9 +353,7 @@
 	ingress_destroy,		/* destroy */
 	NULL,				/* change */
 
-#ifdef CONFIG_RTNETLINK
 	ingress_dump,			/* dump */
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_prio.c linux/net/sched/sch_prio.c
--- linux-2.4.16/net/sched/sch_prio.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_prio.c	Wed Dec  5 16:36:06 2001
@@ -231,7 +231,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
@@ -247,7 +246,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 		      struct Qdisc **old)
@@ -322,7 +320,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
 static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb,
 			   struct tcmsg *tcm)
 {
@@ -334,7 +331,6 @@
 		tcm->tcm_info = q->queues[cl-1]->handle;
 	return 0;
 }
-#endif
 
 static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 {
@@ -381,9 +377,7 @@
 	prio_bind,
 	prio_put,
 
-#ifdef CONFIG_RTNETLINK
 	prio_dump_class,
-#endif
 };
 
 struct Qdisc_ops prio_qdisc_ops =
@@ -403,9 +397,7 @@
 	prio_destroy,
 	prio_tune,
 
-#ifdef CONFIG_RTNETLINK
 	prio_dump,
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_red.c linux/net/sched/sch_red.c
--- linux-2.4.16/net/sched/sch_red.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_red.c	Wed Dec  5 16:36:06 2001
@@ -418,7 +418,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
 int red_copy_xstats(struct sk_buff *skb, struct tc_red_xstats *st)
 {
         RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st);
@@ -456,7 +455,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static void red_destroy(struct Qdisc *sch)
 {
@@ -480,9 +478,7 @@
 	red_destroy,
 	red_change,
 
-#ifdef CONFIG_RTNETLINK
 	red_dump,
-#endif
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c
--- linux-2.4.16/net/sched/sch_sfq.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_sfq.c	Wed Dec  5 16:36:06 2001
@@ -439,7 +439,6 @@
 	MOD_DEC_USE_COUNT;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data;
@@ -461,7 +460,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct Qdisc_ops sfq_qdisc_ops =
 {
@@ -480,9 +478,7 @@
 	sfq_destroy,
 	NULL, /* sfq_change */
 
-#ifdef CONFIG_RTNETLINK
 	sfq_dump,
-#endif
 };
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c
--- linux-2.4.16/net/sched/sch_tbf.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sched/sch_tbf.c	Wed Dec  5 16:36:06 2001
@@ -363,7 +363,6 @@
 	MOD_DEC_USE_COUNT;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
@@ -391,7 +390,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct Qdisc_ops tbf_qdisc_ops =
 {
@@ -410,9 +408,7 @@
 	tbf_destroy,
 	tbf_change,
 
-#ifdef CONFIG_RTNETLINK
 	tbf_dump,
-#endif
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/socket.c linux/net/socket.c
--- linux-2.4.16/net/socket.c	Mon Nov 26 10:35:01 2001
+++ linux/net/socket.c	Wed Dec  5 16:36:05 2001
@@ -67,6 +67,8 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/wanrouter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/cache.h>
@@ -79,11 +81,7 @@
 
 #include <asm/uaccess.h>
 
-#include <linux/inet.h>
-#include <net/ip.h>
 #include <net/sock.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <net/scm.h>
 #include <linux/netfilter.h>
 
@@ -1724,7 +1722,7 @@
 	 * The netlink device handler may be needed early.
 	 */
 
-#ifdef  CONFIG_RTNETLINK
+#ifdef CONFIG_NET
 	rtnetlink_init();
 #endif
 #ifdef CONFIG_NETLINK_DEV
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- linux-2.4.16/net/sunrpc/xprt.c	Mon Nov 26 10:35:01 2001
+++ linux/net/sunrpc/xprt.c	Thu Dec  6 15:47:36 2001
@@ -630,10 +630,14 @@
 			int to_move = cur_len;
 			if (to_move > copied)
 				to_move = copied;
-			if (need_csum)
-				csum = skb_copy_and_csum_bits(skb, offset, cur_ptr,
-							      to_move, csum);
-			else
+			if (need_csum) {
+				unsigned int csum2;
+
+				csum2 = skb_copy_and_csum_bits(skb, offset,
+							       cur_ptr,
+							       to_move, 0);
+				csum = csum_block_add(csum, csum2, offset);
+			} else
 				skb_copy_bits(skb, offset, cur_ptr, to_move);
 			offset += to_move;
 			copied -= to_move;
@@ -647,8 +651,12 @@
 		}
 	}
 	if (need_csum) {
-		if (slack > 0)
-			csum = skb_checksum(skb, offset, slack, csum);
+		if (slack > 0) {
+			unsigned int csum2;
+
+			csum2 = skb_checksum(skb, offset, slack, 0);
+			csum = csum_block_add(csum, csum2, offset);
+		}
 		if ((unsigned short)csum_fold(csum))
 			return -1;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/unix/af_unix.c linux/net/unix/af_unix.c
--- linux-2.4.16/net/unix/af_unix.c	Mon Nov 26 10:35:01 2001
+++ linux/net/unix/af_unix.c	Wed Dec  5 16:36:06 2001
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.123 2001/09/19 04:50:32 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.126 2001/11/13 05:06:28 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
